home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v9n12.arc / PRUNE.ASM < prev    next >
Assembly Source File  |  1990-05-29  |  118KB  |  3,300 lines

  1. ;--------------------------------------------------;
  2. ;  PRUNE * PC Magazine * Michael J. Mefford        ;
  3. ;                                                  ;
  4. ;  Directory tree pruning and grafting utility.    ;
  5. ;--------------------------------------------------;
  6.  
  7. _TEXT          SEGMENT PUBLIC 'CODE'
  8.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  9.                ORG     100H
  10. START:         JMP     MAIN
  11.  
  12. ;              DATA AREA
  13. ;              ---------
  14. SIGNATURE      DB      CR,SPACE,SPACE,SPACE,CR,LF
  15. COPYRIGHT      DB      "PRUNE 1.0 (c) 1990 Ziff Communications Co. ",CR,LF
  16. PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",LF
  17. CRLF           DB      CR,LF
  18.  
  19. SYNTAX         DB      "Syntax:  PRUNE [d:] [d:]",CR,LF,LF
  20.                DB      "$",CTRL_Z
  21.  
  22. TAB            EQU     9
  23. CR             EQU     13
  24. LF             EQU     10
  25. CTRL_Z         EQU     26
  26. SPACE          EQU     32
  27. BOX            EQU     254
  28. VERT_LINE      EQU     179
  29. FF             EQU     12
  30. SHIFT_KEYS     EQU     3
  31. LITTLE_ARROW   EQU     26
  32. ESC_SCAN       EQU     1
  33. Y_SCAN         EQU     15H
  34. N_SCAN         EQU     31H
  35. NOTE           EQU     1046                    ; C
  36.  
  37. COLOR_ATTRIBS  STRUC
  38. B              DB      71H                     ;Blue on lt. gray
  39. W              DB      17H                     ;Lt. gray on blue
  40. C              DB      31H                     ;Blue on cyan
  41. I              DB      1FH                     ;White on blue
  42. D              DB      17H                     ;Lt. gray on blue
  43. COLOR_ATTRIBS  ENDS
  44.  
  45. COLOR          COLOR_ATTRIBS  <>
  46.  
  47. COLOR_ATTR     COLOR_ATTRIBS  <>
  48. MONO_ATTR      COLOR_ATTRIBS  <70H, 07H, 70H, 0FH, 0FH>
  49.  
  50. BORDER_FLAG    DB      0                       ; =1 to disable.
  51.  
  52. COMSPEC        DB      "COMSPEC="
  53. PARAMETER1     DB      30,  "/C DR", 25 DUP (SPACE), CR
  54. PARAMETER2     DB      100, "/C DIRMATCH "
  55. ARGUMENTS      DB      112 DUP (SPACE), CR
  56.  
  57. ENVIRONMENT    DW      ?
  58. COM_LINE_PTR   DW      ?, ?
  59. STACK_SEG      DW      ?
  60. STACK_PTR      DW      ?
  61.  
  62. BREAK          DB      ?
  63. DEFAULT_DRIVE  DB      ?,":",CR
  64.  
  65. CRT_MODE       EQU     49H
  66. CRT_COLS       EQU     4AH
  67. CRT_ROWS       EQU     84H
  68. COLUMNS        DW      ?
  69. CRT_WIDTH      DW      ?
  70. CRT_START      DW      ?
  71. STATUS_REG     DW      3BAH
  72. VIDEO_SEG      DW      0B000H
  73. ROWS           DB      24
  74. LISTING_LEN    DW      ?
  75.  
  76. ROOT           DB      "\ (Root)"
  77. ROOT_LEN       EQU     $ - ROOT
  78. ROOT_DIR       DB      "\",0
  79. DOT_DOT        DB      "..",0
  80. VOL_DRIVE      DB      ?,":\"
  81. STAR_DOT_STAR  DB      "*.*",0
  82. TEMP           DB      "$$$$$$$$",0
  83. E5             DB      0E5H
  84.  
  85. UNNAMED        DB      "UnNamed    "
  86. VOLUME_LEN     EQU     $ - UNNAMED
  87. DRIVE_SPEC     DB      "  Drive "
  88. DRIVE_LETTER   DB      ?,":  Volume ",0
  89. VOLUME_NAME    DW      VOLUME1,VOLUME2
  90. VOLUME1        DB      11 DUP (?),0
  91. VOLUME2        DB      11 DUP (?),0
  92.  
  93. SECTOR_RECORDS DW      ?
  94. ROOT_SECTOR    DW      ?
  95. ROOT_SECTORS   DW      ?
  96. CLUST_RECORDS  DW      ?
  97. LAST_CLUSTER   DW      ?
  98. LAST_ENTRY     DW      ?
  99. TREE_LEVEL     DW      ?
  100.  
  101. DIRS           DW      ?
  102. DIR_COUNT      DW      ?,?
  103. LISTING_TOP    DW      0,0
  104. BAR_LINE       DW      0,0
  105. ACTIVE_TREE    DW      0
  106. TREE_COLOR     DB      ?
  107.  
  108. MAX_ENTRIES    EQU     1000
  109. BUFFER_SEG     LABEL   WORD
  110. FAT_SEG        DW      ?
  111. TREE_DATA_SEG  DW      ?,?
  112. TREE_SEG       DW      ?,?
  113. CLUSTER_SEG    DW      ?
  114. OLD_PARENT     DW      ?
  115. NEW_PARENT     DW      ?
  116.  
  117. BIG_DISK_FLAG  DB      ?
  118. DATA_SECTOR    DW      ?
  119.  
  120. SOURCE_INDEX   DW      ?
  121. SOURCE_POINTER LABEL   DWORD
  122. SOURCE_LINE    DW      ?
  123. MARK_SEG       DW      ?
  124. SOURCE_BAR     DW      ?
  125. DEST_POINTER   LABEL   DWORD
  126. DEST_LINE      DW      ?
  127. DEST_SEG       DW      ?
  128.  
  129. PACKET         LABEL   BYTE
  130. STARTING_SECTOR        DW    ?,?
  131. NUMBER_OF_SECTORS      DW    ?
  132. TRANSFER_ADDRESS       DW    ?,?
  133.  
  134. BPB            LABEL   BYTE
  135. BPB_BytesPerSector     DW    ?
  136. BPB_SectorsPerCluster  DB    ?
  137. BPB_ReservedSectors    DW    ?
  138. BPB_NumberOfFats       DB    ?
  139. BPB_RootEntries        DW    ?
  140. BPB_TotalSectors       DW    ?
  141. BPB_MediaDescriptor    DB    ?
  142. BPB_SectorsPerFat      DW    ?
  143. BPB_LENGTH             EQU   $ - BPB
  144.  
  145. FAT_TYPE       DB      ?
  146. FAT_16_BIT     EQU     0
  147. FAT_12_BIT     EQU     1
  148.  
  149. TREE_DRIVE     DB      ?,?,?
  150. DEFAULT_PATH   DW      OFFSET DEFAULT_DIR1, OFFSET DEFAULT_DIR2
  151.  
  152. FREE_CLUSTERS  DW      ?,?
  153. TOTAL_CLUSTERS DW      ?,?
  154. BYTES_CLUSTERS DW      ?,?
  155. DIRECTORIES    DB      " directories",0
  156. BYTES          DB      " bytes ",0
  157. TOTAL          DB      "total "
  158. PERCENT_100    DB            "100%",0
  159. USED           DB      "used  ",0
  160. FREE           DB      "free  ",0
  161.  
  162. CLUSTER_CNT    DW      ?
  163. TOTAL_FILES    DW      ?
  164. ENTRY_CNT      DW      ?
  165. BRANCH_FLAG    DB      ?
  166. REREAD_FLAG    DB      0
  167.  
  168. BRANCH_NUM     DW      ?
  169.  
  170. DTA            EQU     80H
  171. MATCHING       STRUC
  172. RESERVED       DB      21 DUP (?)
  173. ATTRIBUTE      DB              ?
  174. FILE_TIME      DW              ?
  175. FILE_DATE      DW              ?
  176. SIZE_LOW       DW              ?
  177. SIZE_HIGH      DW              ?
  178. FILE_NAME      DB      13 DUP (?)
  179. MATCHING       ENDS
  180.  
  181. DIR_ENTRY      STRUC
  182. DIR_NAME       DB      8 DUP (?)
  183. DIR_EXT        DB      3 DUP (?)
  184. DIR_ATTR       DB      ?
  185. DIR_RESERVED   DB      10 DUP (?)
  186. DIR_TIME       DW      ?
  187. DIR_DATE       DW      ?
  188. DIR_CLUSTER    DW      ?
  189. DIR_SIZE       DD      ?
  190. DIR_ENTRY      ENDS
  191.  
  192. SOURCE_RECORD  DB      SIZE DIR_ENTRY DUP (?)
  193. DIR_LEN        DW      ?
  194.  
  195. TREE_DATA      STRUC
  196. LEVEL          DB      ?
  197. ENTRY          DW      ?
  198. PARENT         DW      ?
  199. DIRECTORY      DB      11 DUP (?)
  200. CLUSTER        DW      ?
  201. ATTRIB         DW      ?
  202. TREE_DATA      ENDS
  203.  
  204. TREE           STRUC
  205. MARK           DB      ?
  206. BRANCH         DB      38 DUP (?)
  207. TREE_CLUSTER   DW      ?
  208. BRANCH_NO      DW      ?
  209. TREE           ENDS
  210.  
  211. M_DISPATCH     DB      48H,     50H,   49H,   51H,   47H,   4FH
  212.                DB      0FH,     4BH,   4DH
  213.                DB      3BH,         3CH,           3DH,         3EH
  214.                DB      3FH,         40H,      41H,       42H, 43H
  215. M_LEN          EQU     $ - M_DISPATCH
  216.  
  217.                DW      UP,      DOWN,  PGUP,  PGDN,  HOME,  END_KEY
  218.                DW      TAB_KEY, LEFT,  RIGHT
  219.                DW      COPY_BRANCH, REMOVE_BRANCH, RENAME_BRANCH, MOVE_BRANCH
  220.                DW      SIZE_BRANCH, SIZE_DIR, NEW_DRIVE, DR,  DIRMATCH
  221.  
  222. D_DISPATCH     DB      48H,     50H,   49H,   51H,   47H,   4FH
  223.                DB      0FH,     4BH,   4DH
  224. D_LEN          EQU     $ - D_DISPATCH
  225.  
  226.                DW      UP,      DOWN,  PGUP,  PGDN,  HOME,  END_KEY
  227.                DW      TAB_KEY, LEFT,  RIGHT
  228.  
  229. NOT_ENOUGH     DB      "Requires 276K free memory$"
  230. INVALID_DRIVE  DB      "Invalid Drive$"
  231. READING        DB      CR,LF,"Reading Directories",CR,LF,"$"
  232.  
  233. CANT_ROOT      DB "Can't prune, copy or rename root directory.",0
  234. ILLOGICAL_MSG  DB "Illogical to graft to this directory.",0
  235. DUPLICATE_MSG  DB "Directory name already exits.",0
  236. SUBDIR_MSG     DB "Subdirectory creation error; Can't prune.",0
  237. LOGICAL_MSG    DB "Logical error; Can't prune.",0
  238. ANYKEY_MSG     DB "  Press any key to continue.",0
  239. DEST_MSG       DB "Highlight destination directory for branch and press Enter",0
  240. WORKING_MSG    DB "Pruning in progress...",0
  241.  
  242. REMOVE_MSG     LABEL   BYTE
  243. DB "WARNING: All files in marked dir AND it's subdirs will be lost.  Continue"
  244. YES_NO         DB      "?  Y/N ",0
  245.  
  246. REMOVE_MSG2    LABEL   BYTE
  247. DB "Press Enter to confirm and start directory branch removal.  Esc to cancel."
  248. DB             0
  249. TO_MSG         DB      "and any subdirs to ",0
  250. DELETE_MSG     DB      "Removing subdirectories and files...",0
  251.  
  252. FILES_MSG      DB      " files  ",0
  253. CLUSTER_MSG    DB      " cluster bytes",0
  254. SIZE_MSG       DB      "Root size is bytes used.",0
  255.  
  256. DRIVE_MSG      DB      "Enter new drive letter  ",0
  257. DRIVE_MSG_LEN  EQU     $ - DRIVE_MSG
  258. DRIVE_ERR      DB      "Drive does not exist.",0
  259.  
  260. COPY_MSG       DB      "Copying subdirectories and files...",0
  261. ROOM_MSG       DB      "Not enough room to move or copy.",0
  262.  
  263. RENAME_MSG     DB      "Enter new name for ",0
  264. DOS3_MSG       DB      "Requires DOS 3.x or later",0
  265.  
  266. MSG            DW      ?
  267. COPYA          DB      "Copy ",0
  268. MOVEA          DB      "Move ",0
  269.  
  270. MENU           LABEL   BYTE
  271. DB "F1 Copy    F2 Remove    F3 Rename    F4 Move    F5 Branch Size    "
  272. DB "F6 Dir Size   ",0
  273. DB "F7 New Drive   F8 DR   F9 DIRMATCH   Tab "
  274. DB 27,26," Select Tree  ",24,25," Branch   Esc to Exit",0
  275.  
  276.  
  277. ;              CODE AREA
  278. ;              ---------
  279. MAIN           PROC    NEAR
  280.                CLD                             ;String instructions forward.
  281.  
  282.                MOV     AX,3300H                ;Get Ctrl-Break state.
  283.                INT     21H
  284.                MOV     BREAK,DL
  285.  
  286.                MOV     AH,19H                  ;Get default drive so can
  287.                INT     21H                     ; restore after we change it.
  288.                MOV     DEFAULT_DRIVE,AL
  289.  
  290.                MOV     BX,(12+128+64+64+8) * (1024/16)
  291.                MOV     AH,4AH                  ;Allocate memory.
  292.                INT     21H
  293.                JNC     SETUP_STACK
  294.                MOV     DX,OFFSET NOT_ENOUGH
  295.                JMP     ERROR_EXIT              ;If not enough, exit.
  296.  
  297. SETUP_STACK:   MOV     AX,OFFSET STACK_POINTER
  298.                MOV     SP,AX                   ;Set up stack.
  299.                ADD     AX,15
  300.                MOV     CL,4
  301.                SHR     AX,CL
  302.                MOV     CX,DS
  303.                ADD     AX,CX
  304.                MOV     FAT_SEG,AX              ;And data segments.
  305.                ADD     AX,128 * (1024/16)
  306.                MOV     TREE_DATA_SEG[0],AX
  307.                ADD     AX,MAX_ENTRIES * SIZE TREE_DATA / 16 + 1
  308.                MOV     TREE_DATA_SEG[2],AX
  309.                ADD     AX,MAX_ENTRIES * SIZE TREE_DATA / 16 + 1
  310.                MOV     TREE_SEG[0],AX
  311.                ADD     AX,MAX_ENTRIES * SIZE TREE / 16 + 1
  312.                MOV     TREE_SEG[2],AX
  313.                ADD     AX,MAX_ENTRIES * SIZE TREE / 16 + 1
  314.                MOV     CLUSTER_SEG,AX
  315.  
  316. PARSE:         MOV     SI,81H
  317.                XOR     BP,BP                   ;Tree index.
  318. NEXT_PARSE:    LODSB
  319.                CMP     AL,CR
  320.                JNZ     CK_WHITE
  321.                MOV     SI,OFFSET DEFAULT_DRIVE ;Use default drive if no para.
  322.                PUSH    [SI]
  323.                ADD     BYTE PTR [SI],"A"
  324.                LODSB
  325.                CALL    DRIVEEXIST
  326.                POP     WORD PTR DEFAULT_DRIVE
  327.                JMP     SHORT FIRST_DRIVE
  328.  
  329. CK_WHITE:      CMP     AL,SPACE
  330.                JBE     NEXT_PARSE
  331.                CALL    DRIVEEXIST
  332. FIRST_DRIVE:   JNZ     PARSE_ERROR
  333. STORE_DRIVE:   MOV     TREE_DRIVE[0],DL
  334.                CALL    SELECT_DISK
  335.                PUSH    SI
  336.                MOV     SI,DEFAULT_PATH[BP]     ;Get default path so can
  337.                CALL    GET_DIR                 ; restore on exit.
  338.                POP     SI
  339.  
  340.                INC     BP                      ;Next tree.
  341.                INC     BP
  342. NEXT_PARSE2:   LODSB
  343.                CMP     AL,CR
  344.                JZ      PARSE_END
  345.                CMP     AL,SPACE
  346.                JBE     NEXT_PARSE2
  347.                CALL    DRIVEEXIST
  348.                JNZ     PARSE_ERROR
  349.  
  350. PARSE_END:     MOV     TREE_DRIVE[2],DL
  351.                CALL    SELECT_DISK
  352.                MOV     SI,DEFAULT_PATH[BP]
  353.                CALL    GET_DIR
  354.  
  355. BREAK_OFF:     XOR     DL,DL                   ;Turn break off.
  356.                MOV     AX,3301H
  357.                INT     21H
  358.  
  359.                CALL    SETUP
  360.  
  361. ;************* Main Loop *************;
  362.  
  363. NEXT_KEY:      CALL    HIDE_CURSOR
  364.                CALL    CLEAR_KEY
  365.                MOV     DI,OFFSET M_DISPATCH
  366.                MOV     CX,M_LEN
  367.                CALL    DISPATCH
  368.                JNC     NEXT_KEY
  369.                JMP     SHORT EXIT
  370.  
  371. ;----------------------------------------------;
  372. PARSE_ERROR:   MOV     DX,OFFSET INVALID_DRIVE
  373. ERROR_EXIT:    PUSH    DX
  374.                MOV     DX,OFFSET SIGNATURE
  375.                CALL    PRINT_STRING
  376.                POP     DX
  377. ERROR:         CALL    PRINT_STRING            ;Print error message.
  378.                MOV     AL,1                    ;Exit with ERRORLEVEL one.
  379.                JMP     SHORT TERMINATE
  380.  
  381. EXIT:          MOV     DH,ROWS                 ;Clear last two lines.
  382.                MOV     CH,DH
  383.                DEC     CH
  384.                XOR     CL,CL
  385.                MOV     DL,BYTE PTR COLUMNS
  386.                DEC     DL
  387.                MOV     BH,COLOR.B
  388.                MOV     AX,600H                 ; by scrolling active page.
  389.                INT     10H
  390.  
  391.                CMP     BORDER_FLAG,1
  392.                JZ      PLACE_CURSOR
  393.                XOR     BX,BX                   ;Border back to black.
  394.                MOV     AH,0BH
  395.                INT     10H
  396.  
  397. PLACE_CURSOR:  MOV     DH,CH                   ;Place cursor on next
  398.                DEC     DH                      ; to last line.
  399.                XOR     DL,DL
  400.                CALL    SET_CURSOR
  401.                XOR     BP,BP                   ;Restore paths.
  402.                CALL    RESTORE_DIR
  403.                INC     BP
  404.                INC     BP
  405.                CALL    RESTORE_DIR
  406.                XOR     AL,AL                   ;ERRORLEVEL zero.
  407.  
  408. TERMINATE:     PUSH    AX
  409.                MOV     DL,DEFAULT_DRIVE        ;Restore default drive.
  410.                MOV     AH,0EH
  411.                INT     21H
  412.                MOV     DL,BREAK                ;Restore Break state.
  413.                MOV     AX,3301H
  414.                INT     21H
  415.                MOV     AH,0DH                  ;Disk reset to flush buffers.
  416.                INT     21H
  417.                POP     AX
  418.                MOV     AH,4CH                  ;Terminate.
  419.                INT     21H
  420. MAIN           ENDP
  421.  
  422. ;              ***************
  423. ;              * SUBROUTINES *
  424. ;              ***************
  425.  
  426. RENAME_BRANCH: MOV     AH,30H
  427.                INT     21H
  428.                CMP     AL,3
  429.                JAE     CAN_RENAME
  430.                MOV     SI,OFFSET DOS3_MSG
  431.                CALL    DISPLAY_ERROR
  432.                JMP     RENAME_END
  433.  
  434. CAN_RENAME:    MOV     AX,SIZE TREE
  435.                MUL     BAR_LINE[BP]
  436.                MOV     SOURCE_LINE,AX
  437.                OR      AX,AX
  438.                JNZ     DISPLAY_OLD
  439.                MOV     SI,OFFSET CANT_ROOT
  440.                CALL    DISPLAY_ERROR
  441.                JMP     RENAME_END
  442.  
  443. DISPLAY_OLD:   CALL    CLEAR_MENU
  444.                MOV     SI,OFFSET RENAME_MSG
  445.                CALL    WRITE_STRING
  446.                MOV     SI,SOURCE_LINE
  447.                PUSH    SI
  448.                MOV     DS,TREE_SEG[BP]
  449.                CALL    GET_NAME
  450.                MOV     CS:SOURCE_LINE,SI
  451.                CALL    WRITE_STRING
  452.  
  453.                CALL    DOS_CURSOR
  454.                POP     SI
  455.                CALL    SELECT_DIR
  456.                PUSH    CS
  457.                POP     DS
  458.                MOV     DX,OFFSET DOT_DOT
  459.                CALL    CHANGE_DIR
  460.  
  461.                MOV     DH,ROWS
  462.                DEC     DH
  463.                MOV     DL,34
  464.                CALL    SET_CURSOR
  465.                MOV     BX,DX
  466.                MOV     DI,OFFSET ARGUMENTS
  467.  
  468. NEXT_RENAME:   CALL    GET_KEY
  469.                CMP     AL,ESC_SCAN
  470.                JZ      RENAME_END
  471.                CMP     AH,CR
  472.                JZ      DO_RENAME
  473.                XCHG    AL,AH
  474.                CMP     AL,8
  475.                JZ      BACKSPACE
  476.                CMP     AL,SPACE
  477.                JBE     NEXT_RENAME
  478.                CMP     DI,OFFSET ARGUMENTS + 12
  479.                JZ      NEXT_RENAME
  480.                STOSB
  481.                CALL    WRITE_TTY
  482.                JMP     NEXT_RENAME
  483.  
  484. BACKSPACE:     CMP     DI,OFFSET ARGUMENTS
  485.                JZ      NEXT_RENAME
  486.                CALL    WRITE_TTY
  487.                MOV     AL,SPACE
  488.                CALL    WRITE_TTY
  489.                MOV     AL,8
  490.                CALL    WRITE_TTY
  491.                DEC     DI
  492.                JMP     NEXT_RENAME
  493.  
  494. DO_RENAME:     XOR     AL,AL
  495.                STOSB
  496.                CALL    DOS_CURSOR
  497.                MOV     DI,OFFSET ARGUMENTS
  498.                MOV     DX,SOURCE_LINE
  499.                MOV     DS,TREE_SEG[BP]
  500.                MOV     AH,56H
  501.                INT     21H
  502.  
  503.                PUSH    CS
  504.                POP     DS
  505.                JNC     RENAME_END2
  506.                CALL    BEEP
  507.                JMP     SHORT RENAME_END
  508.  
  509. RENAME_END2:   MOV     REREAD_FLAG,1
  510.                JMP     SELECT_UPDATE
  511.  
  512. RENAME_END:    CALL    UPDATE_TREE
  513.                CALL    DISPLAY_MENU
  514.                RET
  515.  
  516. ;----------------------------------------------;
  517.  
  518. MOVE_BRANCH:   MOV     MSG,OFFSET MOVEA
  519.                CALL    GET_DEST                ;Get the destination.
  520.                JC      MOVE_END
  521.                CMP     AL,AH                   ;Same drive?
  522.                JNZ     DO_COPY
  523.  
  524.                CALL    FAST_MOVE               ;If yes, only change dot dot
  525.                JMP     SELECT_UPDATE           ; pointers.
  526.  
  527. DO_COPY:       CALL    COPY                    ;Else, do copy
  528.                JC      READ_DISKS
  529.                CALL    DELETE                  ; then delete.
  530.  
  531. READ_DISKS:    MOV     AX,CS
  532.                MOV     DS,AX
  533.                MOV     ES,AX
  534.                CMP     REREAD_FLAG,1
  535.                JNZ     MOVE_END
  536.                MOV     REREAD_FLAG,0
  537.                CALL    READ_DRIVE              ;Reread both trees.
  538.                XOR     BP,2
  539.                CALL    READ_DRIVE
  540.  
  541. MOVE_END:      MOV     AX,CS
  542.                MOV     DS,AX
  543.                MOV     ES,AX
  544.                CALL    UPDATE_TREE
  545.                CALL    DISPLAY_MENU
  546.                RET
  547.  
  548. ;----------------------------------------------;
  549.  
  550. COPY_BRANCH:   MOV     MSG, OFFSET COPYA
  551.                CALL    GET_DEST                ;Get destination.
  552.                JC      COPY_END3
  553.                CALL    COPY                    ;Copy the branch.
  554.                JMP     SHORT SELECT_UPDATE     ;Update the screen.
  555.  
  556. COPY_END3:     CALL    UPDATE_TREE
  557.                CALL    DISPLAY_MENU
  558.                RET
  559.  
  560. ;----------------------------------------------;
  561.  
  562. REMOVE_BRANCH: MOV     AX,BAR_LINE[BP]         ;Root directory?
  563.                OR      AX,AX
  564.                JNZ     CAUTION
  565.                MOV     SI,OFFSET CANT_ROOT
  566.                CALL    DISPLAY_ERROR
  567.                JMP     SHORT REMOVE_END
  568.  
  569. CAUTION:       CALL    DISPLAY_MARK
  570.                CALL    ERASE_MARK
  571.                CALL    CLEAR_MENU
  572.                MOV     SI,OFFSET REMOVE_MSG    ;Warning message.
  573.                CALL    WRITE_STRING
  574.                CALL    BEEP
  575.                CALL    CLEAR_KEY
  576.  
  577.                CALL    GET_KEY                 ;Get response.
  578.                CMP     AL,Y_SCAN
  579.                JNZ     REMOVE_END
  580.                CALL    CLEAR_MENU
  581.                MOV     SI,OFFSET REMOVE_MSG2
  582.                CALL    WRITE_STRING
  583.                CALL    HIDE_CURSOR
  584.                CALL    CLEAR_KEY
  585.                CALL    GET_KEY
  586.                CMP     AH,CR
  587.                JNZ     REMOVE_END
  588.  
  589.                MOV     DL,TREE_DRIVE[BP]       ;If yes, log on drive.
  590.                CALL    SELECT_DISK
  591.                CALL    DOS_CURSOR
  592.                CALL    DELETE                  ;Delete the branch.
  593.  
  594. SELECT_UPDATE: MOV     AX,CS
  595.                MOV     DS,AX
  596.                MOV     ES,AX
  597.                CMP     REREAD_FLAG,1
  598.                JNZ     REMOVE_END
  599.                MOV     REREAD_FLAG,0
  600.  
  601.                MOV     BX,BP
  602.                XOR     BX,2
  603.                MOV     DL,TREE_DRIVE[BX]       ;If tree drives different,
  604.                CMP     DL,TREE_DRIVE[BP]
  605.                JZ      DUP_DELETE
  606.                CALL    READ_DRIVE              ; just update the one.
  607.                JMP     SHORT REMOVE_END
  608.  
  609. DUP_DELETE:    XOR     BP,BP                   ;Else, if both tree drives same
  610.                CALL    READ_DRIVE              ; then just update one and
  611.                INC     BP
  612.                INC     BP
  613.                CALL    DUP_TREE                ; copy for other.
  614.  
  615. REMOVE_END:    CALL    UPDATE_TREE
  616.                CALL    DISPLAY_MENU
  617.                RET
  618.  
  619. ;----------------------------------------------;
  620.  
  621. SIZE_DIR:      MOV     BRANCH_FLAG,0           ;Just the one directory.
  622.                JMP     SHORT CALC_CLUST
  623.  
  624. SIZE_BRANCH:   MOV     BRANCH_FLAG,1           ;Directory and it's subdirs.
  625. CALC_CLUST:    PUSH    DS
  626.                MOV     BX,BYTES_CLUSTERS[BP]   ;Use current tree's cluster size.
  627.                MOV     AX,SIZE TREE
  628.                MUL     BAR_LINE[BP]
  629.                MOV     SI,AX
  630.                OR      SI,SI                   ;Root directory?
  631.                JZ      BRANCH_ERR1
  632.  
  633.                PUSH    SI
  634.                PUSH    BX
  635.                CALL    DISPLAY_MARK
  636.                CALL    ERASE_MARK
  637.                POP     BX
  638.                POP     SI
  639.  
  640.                MOV     DS,TREE_SEG[BP]
  641.                CALL    CALC_BRANCH             ;Calculate size.
  642.                MOV     SI,OFFSET LOGICAL_MSG
  643.                JC      BRANCH_ERR
  644.                POP     DS
  645.                PUSH    BX
  646.                CALL    CLEAR_MENU
  647.  
  648.                ADD     DI,2 * 17
  649.                MOV     AL,COLOR.C
  650.                MOV     TREE_COLOR,AL
  651.                MOV     AX,CLUSTER_CNT          ;Display size stats.
  652.                POP     SI
  653.                MUL     SI
  654.                CALL    DISP_STATS
  655.                MOV     SI,OFFSET CLUSTER_MSG
  656.                CALL    WRITE_STRING
  657.  
  658.                ADD     DI,2*8
  659.                MOV     AX,TOTAL_FILES          ;Total file count.
  660.                XOR     DX,DX
  661.                CALL    DISP_STATS
  662.                MOV     SI,OFFSET FILES_MSG
  663.                CALL    WRITE_STRING
  664.  
  665.                MOV     SI,OFFSET ANYKEY_MSG
  666.                CALL    WRITE_STRING
  667.                CALL    HIDE_CURSOR
  668.                CALL    CLEAR_KEY
  669.                CALL    GET_KEY                 ;Pause.
  670.                CALL    UPDATE_TREE
  671.                CALL    DISPLAY_MENU
  672.                RET
  673.  
  674. BRANCH_ERR1:   MOV     SI,OFFSET SIZE_MSG
  675. BRANCH_ERR:    CALL    DISPLAY_ERROR
  676.                POP     DS
  677.                RET
  678.  
  679. ;----------------------------------------------;
  680.  
  681. NEW_DRIVE:     CALL    DOS_CURSOR
  682.                CALL    RESTORE_DIR             ;Restore current path.
  683. NEW_DRIVE2:    CALL    CLEAR_MENU
  684.                MOV     SI,OFFSET DRIVE_MSG
  685.                CALL    WRITE_STRING
  686.                MOV     DH,ROWS
  687.                DEC     DH
  688.                MOV     DL,DRIVE_MSG_LEN - 1
  689.                CALL    SET_CURSOR
  690.                JMP     SHORT GET_DRIVE
  691.  
  692. BAD_DRIVE:     CALL    BEEP
  693. GET_DRIVE:     CALL    GET_KEY                 ;Get new drive letter.
  694.  
  695.                CMP     AL,ESC_SCAN
  696.                JZ      DRIVE_RET
  697.                AND     AH,5FH                  ;Capitalize.
  698.                CMP     AH,"A"
  699.                JB      BAD_DRIVE
  700.                CMP     AH,"Z"
  701.                JA      BAD_DRIVE
  702.  
  703.                PUSH    AX
  704.                MOV     SI,OFFSET DEFAULT_DRIVE
  705.                PUSH    [SI]
  706.                MOV     [SI],AH
  707.                MOV     AL,AH
  708.                CALL    WRITE_SCREEN
  709.                LODSB
  710.                CALL    DRIVEEXIST              ;Does drive exist?
  711.                POP     WORD PTR DEFAULT_DRIVE
  712.                POP     AX
  713.                JZ      GET_DRIVE2
  714.                MOV     SI,OFFSET DRIVE_ERR
  715.                CALL    DISPLAY_ERROR
  716.                JMP     NEW_DRIVE2
  717.  
  718. GET_DRIVE2:    SUB     AH,"A"
  719.                PUSH    WORD PTR TREE_DRIVE[BP]
  720.                MOV     TREE_DRIVE[BP],AH       ;Save new drive.
  721.                CALL    READ_DRIVE              ;Read it.
  722.                POP     AX
  723.                JNC     DRIVE_DONE
  724.                MOV     TREE_DRIVE[BP],AL
  725.                CALL    BEEP
  726.                JMP     NEW_DRIVE2              ;If error, prompt again.
  727.  
  728. DRIVE_DONE:    MOV     BAR_LINE[BP],0
  729.                MOV     LISTING_TOP[BP],0
  730.                CALL    CLEAR_DRIVE             ;Display new tree.
  731.                CALL    DISPLAY_DRIVE
  732.  
  733. DRIVE_RET:     CALL    DISPLAY_MENU
  734.                RET
  735.  
  736. ;----------------------------------------------;
  737.  
  738. FIRST_MSG      DB      "Highlight 1st directory to match and press Enter",0
  739. SECOND_MSG     DB      "Now highlight 2nd directory and press Enter",0
  740.  
  741. DIRMATCH:      CALL    CLEAR_MENU
  742.                MOV     SI,OFFSET FIRST_MSG
  743.                CALL    WRITE_STRING
  744.  
  745. NEXT_1ST:      MOV     DI,OFFSET D_DISPATCH
  746.                MOV     CX,D_LEN
  747.                CALL    DISPATCH                ;Get destination.
  748.                JC      DIRMATCH_END            ;Abort if Esc.
  749.                CMP     AH,CR                   ;Carriage return if selected.
  750.                JNZ     NEXT_1ST
  751.  
  752.                CALL    DISPLAY_MARK
  753.                CALL    CLEAR_MENU
  754.                MOV     SI,OFFSET SECOND_MSG
  755.                CALL    WRITE_STRING
  756.  
  757.                MOV     DI,OFFSET ARGUMENTS
  758.                MOV     DX,BAR_LINE[BP]
  759.                CALL    MAKE_DIR
  760.  
  761. NEXT_2ND:      PUSH    DI
  762.                MOV     DI,OFFSET D_DISPATCH
  763.                MOV     CX,D_LEN
  764.                CALL    DISPATCH                ;Get destination.
  765.                POP     DI
  766.                JC      DIRMATCH_END2           ;Abort if Esc.
  767.                CMP     AH,CR                   ;Carriage return if selected.
  768.                JNZ     NEXT_2ND
  769.  
  770.                MOV     DX,BAR_LINE[BP]
  771.                CALL    MAKE_DIR
  772.                MOV     AX,OFFSET PARAMETER2
  773.                JMP     SHORT EXEC
  774.  
  775. DIRMATCH_END2: CALL    ERASE_MARK
  776. DIRMATCH_END:  CALL    UPDATE_TREE
  777.                CALL    DISPLAY_MENU
  778.                RET
  779.  
  780. ;----------------------------------------------;
  781. ; INPUT: DX = Line number
  782.  
  783. MAKE_DIR:      PUSH    DS
  784.                MOV     AL,TREE_DRIVE[BP]
  785.                ADD     AL,"A"
  786.                STOSB
  787.                MOV     AL,":"
  788.                STOSB
  789.  
  790.                MOV     AX,SIZE TREE
  791.                MUL     DX
  792.                MOV     SI,AX
  793.                MOV     DS,TREE_SEG[BP]
  794.                CALL    GET_NAME
  795.                XOR     CX,CX
  796.  
  797. NEXT_PATH:     CMP     SI,1
  798.                JBE     NEXT_MAKE4
  799.                PUSH    SI
  800.                CALL    FIND_PARENT
  801.                INC     CX
  802.                JMP     NEXT_PATH
  803.  
  804. NEXT_MAKE4:    MOV     AL,"\"
  805.                STOSB
  806.                JCXZ    PATH_END
  807.                POP     SI
  808. NEXT_MAKE5:    LODSB
  809.                OR      AL,AL
  810.                JZ      LOOP_MAKE
  811.                STOSB
  812.                JMP     NEXT_MAKE5
  813. LOOP_MAKE:     LOOP    NEXT_MAKE4
  814.  
  815. PATH_END:      MOV     AL,SPACE
  816.                STOSB
  817.                MOV     AL,CR
  818.                STOSB
  819.                DEC     DI
  820.                POP     DS
  821.                RET
  822.  
  823. ;----------------------------------------------;
  824.  
  825. DR:            MOV     AX,OFFSET PARAMETER1
  826.  
  827. ;----------------------------------------------;
  828.  
  829. EXEC:          MOV     COM_LINE_PTR[0],AX
  830.                MOV     COM_LINE_PTR[2],DS
  831.  
  832.                PUSH    DS
  833.                PUSH    ES
  834.                MOV     DL,TREE_DRIVE[BP]       ;Log on to current tree drive.
  835.                CALL    SELECT_DISK
  836.                MOV     AX,SIZE TREE
  837.                MUL     BAR_LINE[BP]
  838.                MOV     SI,AX
  839.                MOV     DS,TREE_SEG[BP]
  840.                CALL    SELECT_DIR              ;And highlighted directory.
  841.                PUSH    CS
  842.                POP     DS
  843.  
  844.                MOV     BX,OFFSET STACK_POINTER
  845.                ADD     BX,15
  846.                MOV     CL,4
  847.                SHR     BX,CL
  848.                MOV     AX,CS
  849.                ADD     BX,AX
  850.                MOV     AH,4AH                  ;Deallocate memory.
  851.                INT     21H
  852.  
  853.                CALL    DOS_CURSOR
  854.                MOV     BH,COLOR.D              ;White on blue.
  855.                CALL    CLS2                    ;Clear screen.
  856.                CLI
  857.                MOV     STACK_SEG,SS            ;Save stack segment and pointer.
  858.                MOV     STACK_PTR,SP
  859.                STI
  860.  
  861.                MOV     AX,DS:[2CH]                ;Retrieve environment segment.
  862.                MOV     ENVIRONMENT,AX             ;And put in paramter block.
  863.                MOV     DS,AX
  864.  
  865.                XOR     AX,AX                 ;Zero out pointer.
  866. FIND_COMSPEC:  MOV     SI,AX                 ;Point to environment offset.
  867.                INC     AX                    ;Next offset.
  868.                MOV     DI,OFFSET COMSPEC     ;Find "Comspec=".
  869.                MOV     CX,8
  870.                REP     CMPSB
  871.                JNZ     FIND_COMSPEC
  872.                MOV     DX,SI                  ;What follows is Command.com path.
  873.                MOV     BX,OFFSET ENVIRONMENT  ;Point to parameter block.
  874.                MOV     AX,4B00H               ;Execute.
  875.                INT     21H
  876.  
  877.                CLI
  878.                MOV     SP,CS:STACK_PTR       ;Restore stack segment and pointer.
  879.                MOV     SS,CS:STACK_SEG
  880.                STI
  881.                POP     ES                      ;Restore segment registers.
  882.                POP     DS
  883.  
  884.                MOV     DX,80H                  ;Restore Disk Transfer Address.
  885.                MOV     AH,1AH
  886.                INT     21H
  887.                MOV     BX,(12+128+64+64+8) * (1024/16)
  888.                MOV     AH,4AH                  ;Reallocate memory.
  889.                INT     21H
  890.                JNC     RESTORE_DISP
  891.                MOV     DX,OFFSET NOT_ENOUGH    ;Exit if not enough.
  892.                JMP     ERROR_EXIT
  893.  
  894. RESTORE_DISP:  CALL    SETUP
  895.                RET
  896.  
  897. ;**********************************************;
  898.  
  899. ;----------------------------------------------;
  900. ; INPUT:  DS:SI = SOURCE_POINTER -> Source; ES:DI = DEST_POINTER -> Destination
  901. ;         AL and AH = drive; BX = SOURCE_INDEX; BP = Destination index.
  902. ; OUTPUT: CF=1 if failed.
  903.  
  904. COPY:          CALL    CK_DUPLICATE            ;Does branch name already exist?
  905.                JNC     CK_IF_ROOT
  906.                JMP     COPY_END2
  907.  
  908. CK_IF_ROOT:    MOV     AX,CS
  909.                MOV     DS,AX
  910.                MOV     ES,AX
  911.                CMP     DEST_LINE,0             ;Destination root directory?
  912.                JNZ     SETUP_DEST
  913.                CALL    CREATE_TEMP             ;If yes, create and delete
  914.                JNC     SETUP_DEST              ; temporary directory in root
  915.                CALL    FAST_ERROR2             ; to make sure there is room.
  916.                JMP     SHORT COPY_END2
  917.  
  918. SETUP_DEST:    MOV     DL,TREE_DRIVE[BP]       ;Log on destination drive.
  919.                MOV     AL,DL
  920.                ADD     AL,"A"
  921.                MOV     DI,OFFSET DEST_SPEC     ;Create destination spec.
  922.                STOSB
  923.                MOV     AL,":"
  924.                STOSB
  925.                MOV     SI,DI
  926.                CALL    GET_DIR
  927.  
  928. FIND_FILES:    MOV     BRANCH_FLAG,1           ;Calculate source requirement
  929.                MOV     AX,BYTES_CLUSTERS[BP]   ; using destination cluster
  930.                PUSH    BP                      ; size.
  931.                PUSH    BX
  932.                MOV     BP,BX
  933.                MOV     BX,AX
  934.                LDS     SI,SOURCE_POINTER
  935.                CALL    CALC_BRANCH
  936.                POP     BX
  937.                POP     BP
  938.                JC      COPY_END2
  939.  
  940.                PUSH    CS
  941.                POP     DS
  942.                MOV     AX,FREE_CLUSTERS[BP]    ;Is there enough room on
  943.                CMP     AX,CLUSTER_CNT          ; target?
  944.                JAE     ROOM
  945.                MOV     SI,OFFSET ROOM_MSG
  946.                CALL    DISPLAY_ERROR
  947.                JMP     SHORT COPY_END2
  948.  
  949. ROOM:          MOV     DL,TREE_DRIVE[BX]       ;Log onto source drive.
  950.                CALL    SELECT_DISK
  951.                CALL    CONFIRM
  952.                JC      COPY_END2
  953.                CALL    CLEAR_MENU
  954.                MOV     SI,OFFSET COPY_MSG      ;Copy message.
  955.                CALL    WRITE_STRING
  956.                MOV     REREAD_FLAG,1
  957.  
  958.                PUSH    BP
  959.                MOV     SI,OFFSET DEST_SPEC     ;Find end of destination
  960. NEXT_SPEC:     LODSB                           ; spec.
  961.                OR      AL,AL
  962.                JNZ     NEXT_SPEC
  963.                DEC     SI
  964.                MOV     BP,SI
  965.  
  966.                LDS     SI,SOURCE_POINTER       ;Log onto source directory.
  967.                CALL    SELECT_DIR
  968.                CALL    GET_NAME
  969.                MOV     DX,SI
  970.                CALL    GET_DIRS2               ;Copy branch.
  971.                POP     BP
  972.  
  973. COPY_END2:     RET
  974.  
  975. ;----------------------------------------------;
  976. ; OUTPUT: CF=1 if unsuccessful.
  977.  
  978. MAKE_COPY:     MOV     DX,SI
  979.                CALL    CHANGE_DIR              ;Next source subdir.
  980.                JC      MAKE_COPY_END
  981.  
  982. GET_DIRS2:     PUSH    BP
  983.                PUSH    DS
  984.                CALL    MAKE_SPEC               ;Make destination spec.
  985.                MOV     BP,DI                   ;Save end of spec pointer
  986.                DEC     BP                      ; as start of next sub
  987.                MOV     AX,CS                   ; dir appendage.
  988.                MOV     DS,AX
  989.                MOV     DX,OFFSET DEST_SPEC
  990.                MOV     AH,39H                  ;Create a directory.
  991.                INT     21H
  992.                JC      MAKE_DONE
  993.                OR      CL,CL                   ;Is it a hidden directory?
  994.                JZ      GET_FILE
  995.                MOV     CX,2                    ;If yes, make dest hidden also.
  996.                MOV     AX,4301H
  997.                INT     21H
  998.  
  999. GET_FILE:      MOV     DX,OFFSET STAR_DOT_STAR
  1000.                MOV     CX,3                    ;Normal, hidden and read-only.
  1001.                MOV     AH,4EH                  ;Find first matching file.
  1002.                INT     21H
  1003.                JC      NEXT_SUB3
  1004.                JMP     SHORT MAKE_FILE
  1005.  
  1006. NEXT_FILE2:    MOV     AH,4FH                  ;Find next matching file.
  1007.                INT     21H
  1008.                JC      NEXT_SUB3
  1009. MAKE_FILE:     CALL    CREATE                  ;Copy the file to destination
  1010.                JNC     NEXT_FILE2              ; directory.
  1011.                JMP     SHORT MAKE_DONE
  1012.  
  1013. NEXT_SUB3:     POP     DS
  1014.                ADD     SI,SIZE TREE            ;Next record.
  1015. NEXT_SUB4:     CMP     BYTE PTR [SI + 1],"─"   ;Is there another branch?
  1016.                JNZ     DIR_DONE2
  1017.                INC     SI
  1018.                INC     SI
  1019.                CALL    MAKE_COPY               ;If yes, copy it.
  1020.                JC      MAKE_DONE2
  1021.                DEC     SI
  1022.                DEC     SI
  1023.                JMP     NEXT_SUB4
  1024.  
  1025. DIR_DONE2:     PUSH    DS
  1026.                PUSH    CS
  1027.                POP     DS
  1028.                MOV     DX,OFFSET DOT_DOT       ;Return to parent dir.
  1029.                CALL    CHANGE_DIR
  1030. MAKE_DONE:     POP     DS
  1031. MAKE_DONE2:    POP     BP
  1032. MAKE_COPY_END: RET
  1033.  
  1034. ;----------------------------------------------;
  1035. ; OUTPUT: CF=1 if failed.
  1036.  
  1037. CREATE:        PUSH    SI
  1038.                MOV     DX,DTA.FILE_NAME        ;Add file name to destination
  1039.                CALL    MAKE_SPEC               ; spec.
  1040.                MOV     AX,3D00H                ;Open for reading.
  1041.                INT     21H
  1042.                JC      CREATE_END
  1043.                MOV     DI,AX                   ;Read handle.
  1044.  
  1045.                MOV     CL,DS:[DTA.ATTRIBUTE]   ;File attribute.
  1046.                XOR     CH,CH
  1047.                MOV     DX,OFFSET DEST_SPEC
  1048.                MOV     AH,3CH                  ;Create file.
  1049.                INT     21H
  1050.                JC      CLOSE_READ
  1051.                MOV     SI,AX                   ;Write handle.
  1052.  
  1053.                MOV     DS,BUFFER_SEG           ;Read/write buffer.
  1054.                XOR     DX,DX                   ;Offset zero.
  1055.  
  1056. COPY_READ:     MOV     BX,DI                   ;Retrieve read handle.
  1057.                MOV     CX,0FFFFH               ;Full read.
  1058.                MOV     AH,3FH
  1059.                INT     21H                     ;Read source file.
  1060.                JC      CLOSE_WRITE             ;If carry, failed; exit.
  1061.                OR      AX,AX                   ;If zero bytes read, done.
  1062.                JZ      CHANGE_DATE             ;Change target date to source.
  1063.  
  1064.                MOV     CX,AX                   ;Else, bytes read into counter.
  1065.                MOV     BX,SI                   ;Retrieve write handle.
  1066.                MOV     AH,40H
  1067.                INT     21H                     ;Write the buffer to disk.
  1068.                JC      CLOSE_WRITE             ;If failed, exit.
  1069.                CMP     CX,AX                   ;Write same number as read?
  1070.                STC                             ;Assume no.
  1071.                JNZ     CLOSE_WRITE             ;If no, failed; exit.
  1072.                INC     CX                      ;Was it a full read?
  1073.                JZ      COPY_READ               ;If yes, there must be more.
  1074.  
  1075. CHANGE_DATE:   PUSH    CS
  1076.                POP     DS
  1077.                MOV     BX,SI                   ;Write handle.
  1078.                MOV     CX,DS:[DTA.FILE_TIME]   ;Else, make time/date same
  1079.                MOV     DX,DS:[DTA.FILE_DATE]   ; as source.
  1080.                MOV     AX,5701H
  1081.                INT     21H
  1082.  
  1083. CLOSE_WRITE:   PUSHF                           ;Save error if any.
  1084.                MOV     BX,SI                   ;Close write file.
  1085.                MOV     AH,3EH
  1086.                INT     21H
  1087.                POP     AX                      ;Retrieve flags.
  1088.                JC      CLOSE_READ              ;Close successful?
  1089.                XCHG    AH,AL                   ;If no, exit with error, else
  1090.                SAHF                            ; retrieve write state.
  1091.  
  1092. CLOSE_READ:    PUSHF                           ;Save flags.
  1093.                MOV     BX,DI                   ;Close read file.
  1094.                MOV     AH,3EH
  1095.                INT     21H
  1096.                POPF                            ;Write file status.
  1097.  
  1098. CREATE_END:    POP     SI
  1099.                RET
  1100.  
  1101. ;----------------------------------------------;
  1102. ; OUTPUT: CL=directory attribute "H" if hidden.
  1103.  
  1104. MAKE_SPEC:     PUSH    SI
  1105.                MOV     SI,DX
  1106.                MOV     DI,BP                   ;Current spec end.
  1107.                MOV     AL,"\"
  1108.                CMP     BYTE PTR ES:[DI-1],AL   ;Add backslash delimiter
  1109.                JZ      NEXT_MAKE2              ; if necessary.
  1110.                STOSB
  1111. NEXT_MAKE2:    LODSB                           ;Add sub dir or file name.
  1112.                STOSB
  1113.                OR      AL,AL
  1114.                JNZ     NEXT_MAKE2
  1115.                LODSB
  1116.                MOV     CL,AL                   ;Return directory attribute.
  1117.                POP     SI
  1118.                RET
  1119.  
  1120. ;----------------------------------------------;
  1121. ; OUTPUT: DS:SI = SOURCE_POINTER -> Source; ES:DI = DEST_POINTER -> Destination
  1122. ;         AL and AH = drive; BX = SOURCE_INDEX; BP = Destination index.
  1123. ;         CF=1 if abort.
  1124.  
  1125. GET_DEST:      MOV     AX,BAR_LINE[BP]
  1126.                OR      AX,AX                   ;Root directory?
  1127.                JNZ     GET_DEST2
  1128.                MOV     SI,OFFSET CANT_ROOT
  1129.                CALL    DISPLAY_ERROR
  1130.                STC
  1131.                JMP     SHORT DEST_END
  1132.  
  1133. GET_DEST2:     CALL    DISPLAY_MARK
  1134.                CALL    CLEAR_MENU
  1135.                MOV     SI,OFFSET DEST_MSG      ;Destination message.
  1136.                CALL    WRITE_STRING
  1137.  
  1138. GET_DEST3:     PUSH    ACTIVE_TREE
  1139.  
  1140. NEXT_DEST2:    MOV     DI,OFFSET D_DISPATCH
  1141.                MOV     CX,D_LEN
  1142.                CALL    DISPATCH                ;Get destination.
  1143.                JC      ABORT_DEST              ;Abort if Esc.
  1144.                CMP     AH,CR                   ;Carriage return if selected.
  1145.                JNZ     NEXT_DEST2
  1146.  
  1147.                CALL    ERASE_MARK
  1148.                POP     BX                      ;BX=Source Tree
  1149.                MOV     SOURCE_INDEX,BX
  1150.                MOV     AX,SIZE TREE
  1151.                MUL     BAR_LINE[BP]
  1152.                MOV     DI,AX                   ;Destination address.
  1153.                MOV     DEST_LINE,AX
  1154.                MOV     AX,TREE_SEG[BP]         ;Destination segment.
  1155.                MOV     ES,AX
  1156.                MOV     DEST_SEG,AX
  1157.                MOV     AL,TREE_DRIVE[BX]       ;Source drive.
  1158.                MOV     AH,TREE_DRIVE[BP]       ;Destination drive.
  1159.                MOV     SI,SOURCE_LINE          ;Source address.
  1160.                MOV     DS,TREE_SEG[BX]         ;Source seg.
  1161.                CLC
  1162. DEST_END:      RET
  1163.  
  1164. ABORT_DEST:    CALL    ERASE_MARK
  1165.                ADD     SP,2
  1166.                STC
  1167.                RET
  1168.  
  1169. ;----------------------------------------------;
  1170.  
  1171. CONFIRM:       PUSH    DS
  1172.                CALL    HIDE_CURSOR
  1173.                CALL    CLEAR_MENU
  1174.                MOV     SI,MSG
  1175.                CALL    WRITE_STRING
  1176.  
  1177.                PUSH    BP
  1178.                MOV     BP,SOURCE_INDEX
  1179.                MOV     DX,SOURCE_BAR
  1180.                CALL    DISPLAY_PATH
  1181.                POP     BP
  1182.  
  1183.                MOV     SI,OFFSET TO_MSG
  1184.                CALL    WRITE_STRING
  1185.  
  1186.                MOV     DX,BAR_LINE[BP]
  1187.                CALL    DISPLAY_PATH
  1188.                MOV     SI,OFFSET YES_NO
  1189.                CALL    WRITE_STRING
  1190.                CALL    CLEAR_KEY
  1191.                CALL    GET_KEY
  1192.                CMP     AL,Y_SCAN
  1193.                CLC
  1194.                JZ      CONFIRM_END
  1195.                STC
  1196.  
  1197. CONFIRM_END:   PUSHF
  1198.                CALL    DOS_CURSOR
  1199.                POPF
  1200.                POP     DS
  1201.                RET
  1202.  
  1203. ;----------------------------------------------;
  1204. ; INPUT: DX = Bar line.
  1205.  
  1206. DISPLAY_PATH:  PUSH    DI
  1207.                MOV     DI,OFFSET ARGUMENTS
  1208.                CALL    MAKE_DIR
  1209.                MOV     DX,DI
  1210.                POP     DI
  1211.  
  1212.                MOV     SI,OFFSET ARGUMENTS
  1213.                CMP     DX,OFFSET ARGUMENTS + 26
  1214.                JBE     DISPLAY_PATH2
  1215.                PUSH    DX
  1216.                MOV     BYTE PTR ARGUMENTS + 2,0
  1217.                CALL    WRITE_STRING
  1218.                MOV     SI,OFFSET DOT_DOT
  1219.                CALL    WRITE_STRING
  1220.                POP     SI
  1221.                SUB     SI,22
  1222. DISPLAY_PATH2: CALL    WRITE_STRING
  1223.                RET
  1224.  
  1225. ;----------------------------------------------;
  1226. ; INPUT:  DS:SI -> Directory; BP=Index tree; BX=Bytes/cluster; Recursive Proc.
  1227. ; OUTPUT: CLUSTER_CNT=Total clusters of files; CF=1 if unsucessful.
  1228.  
  1229. CALC_BRANCH:   PUSH    BX
  1230.                CALL    DOS_CURSOR
  1231.                MOV     CS:TOTAL_FILES,0        ;Initialize variables.
  1232.                MOV     CS:CLUSTER_CNT,0
  1233.                MOV     DL,TREE_DRIVE[BP]       ;Log onto target drive
  1234.                CALL    SELECT_DISK             ; and directory.
  1235.                CALL    SELECT_DIR
  1236.                JC      CALC_END
  1237.                CALL    GET_NAME
  1238.                CALL    GET_DIRS                ;Get size of branch.
  1239.                PUSHF
  1240.                CALL    HIDE_CURSOR
  1241.                POPF
  1242.                POP     BX
  1243. CALC_END:      RET
  1244.  
  1245. ;----------------------------------------------;
  1246.  
  1247. CALC_DIR:      MOV     DX,SI
  1248.                CALL    CHANGE_DIR              ;Log on to next subdir.
  1249.                JC      DIR_END
  1250.  
  1251. GET_DIRS:      PUSH    DS
  1252.                MOV     AX,CS
  1253.                MOV     DS,AX
  1254.                MOV     ENTRY_CNT,2             ;Dot and dot dot entries.
  1255.                MOV     DX,OFFSET STAR_DOT_STAR
  1256.                MOV     CX,3                    ;Normal, hidden and read-only.
  1257.                CMP     BRANCH_FLAG,1
  1258.                JNZ     FIND_FIRST
  1259.                OR      CX,10H                  ;Find sub dirs if branch count.
  1260. FIND_FIRST:    MOV     AH,4EH
  1261.                INT     21H
  1262.                JC      DIR_SPACE
  1263.                JMP     SHORT CK_FILE
  1264.  
  1265. NEXT_FILE:     MOV     AH,4FH
  1266.                INT     21H
  1267.                JC      DIR_SPACE
  1268. CK_FILE:       CMP     BYTE PTR DS:[DTA.FILE_NAME],"."  ;Skip dot and dot dot.
  1269.                JZ      NEXT_FILE
  1270.                INC     ENTRY_CNT
  1271.                TEST    DS:[DTA.ATTRIBUTE],10H
  1272.                JNZ     NEXT_FILE
  1273.                INC     TOTAL_FILES
  1274.  
  1275.                MOV     AX,DS:[DTA.SIZE_LOW]    ;Calculate cluster bytes
  1276.                MOV     DX,DS:[DTA.SIZE_HIGH]   ; for file.
  1277.                CALL    CALC_TOTAL
  1278.                JMP     NEXT_FILE
  1279.  
  1280. DIR_SPACE:     MOV     AX,ENTRY_CNT            ;Calculate cluster bytes
  1281.                MOV     CX,32                   ; for directory.
  1282.                MUL     CX
  1283.                CALL    CALC_TOTAL
  1284.  
  1285.                ADD     SI,SIZE TREE            ;Next subdir.
  1286.                CMP     BRANCH_FLAG,1
  1287.                POP     DS
  1288.                CLC
  1289.                JNZ     DIR_END
  1290.  
  1291. NEXT_SUB2:     CMP     BYTE PTR [SI + 1],"─"
  1292.                JNZ     DIR_DONE
  1293.                INC     SI
  1294.                INC     SI
  1295.                CALL    CALC_DIR                ;Next branch.
  1296.                JC      DIR_END
  1297.                DEC     SI
  1298.                DEC     SI
  1299.                JMP     NEXT_SUB2
  1300.  
  1301. DIR_DONE:      PUSH    DS
  1302.                PUSH    CS
  1303.                POP     DS
  1304.                MOV     DX,OFFSET DOT_DOT       ;Parent directory.
  1305.                CALL    CHANGE_DIR
  1306.                POP     DS
  1307. DIR_END:       RET
  1308.  
  1309. ;----------------------------------------------;
  1310. ; INPUT:  DX:AX = file or subdir size; BX = Destination bytes/cluster.
  1311.  
  1312. CALC_TOTAL:    DIV     BX
  1313.                OR      DX,DX
  1314.                JZ      SUB_TOTAL
  1315.                INC     AX                      ;Round up.
  1316. SUB_TOTAL:     ADD     CLUSTER_CNT,AX
  1317.                RET
  1318.  
  1319. ;----------------------------------------------;
  1320. ; INPUT: DS:SI -> Source; ES:DI -> Destination; AL and AH = drive.
  1321. ;        Tree's contents of DS:SI and ES:DI are identical.
  1322.  
  1323. FAST_MOVE:     OR      DI,DI                   ;Is destination, root?
  1324.                JNZ     CK_IF_SAME
  1325.                CMP     BRANCH[SI],"├"          ;Is source root directory?
  1326.                JNZ     DO_FAST
  1327.                JMP     FAST_ERROR
  1328.  
  1329. CK_IF_SAME:    MOV     CX,BRANCH_NO[SI]
  1330.                CMP     CX,BRANCH_NO[DI]
  1331.                JNZ     DO_FAST
  1332.  
  1333.                CMP     SI,DI                   ;Source line, destination line.
  1334.                JNZ     SAVE_POINTER
  1335.                JMP     FAST_ERROR              ;Can't graft to same.
  1336. SAVE_POINTER:  PUSH    SI
  1337.                JB      CK_ANCESTOR             ;If below, see if in same branch.
  1338.  
  1339. CK_PARENT:     MOV     DX,CS:SOURCE_BAR        ;Else, see if destination is
  1340.                CALL    GET_NAME                ; parent dir.
  1341.                CALL    FIND_PARENT
  1342.                POP     SI
  1343.                CMP     DX,CS:BAR_LINE[BP]
  1344.                JNZ     DO_FAST
  1345.                JMP     FAST_ERROR
  1346.  
  1347. CK_ANCESTOR:   MOV     SI,DI                   ;Can't graft farther out
  1348.                CALL    GET_NAME                ; in same branch.
  1349.                MOV     DX,CS:BAR_LINE[BP]
  1350. NEXT_ANCESTOR: CALL    FIND_PARENT
  1351.                CMP     DX,CS:SOURCE_BAR
  1352.                JNZ     CK_ABOVE
  1353.                JMP     ANCESTOR_ERR
  1354. CK_ABOVE:      JA      NEXT_ANCESTOR
  1355.                POP     SI
  1356.  
  1357. DO_FAST:       CALL    CK_DUPLICATE            ;Can't graft if name already
  1358.                JNC     FAST_READY              ; exists.
  1359.                JMP     FAST_END
  1360.  
  1361. FAST_READY:    MOV     AX,CS
  1362.                MOV     DS,AX
  1363.                MOV     ES,AX
  1364.  
  1365.                CALL    CONFIRM
  1366.                JNC     WORKING
  1367.                JMP     FAST_END
  1368.  
  1369. WORKING:       CALL    CLEAR_MENU
  1370.                MOV     SI,OFFSET WORKING_MSG
  1371.                CALL    WRITE_STRING
  1372.  
  1373.                CALL    CREATE_TEMP             ;Create/delete to make sure
  1374.                JNC     FAST_BOOT               ; there is a free space.
  1375.                JMP     FAST_ERROR2
  1376.  
  1377. FAST_BOOT:     CALL    GET_BOOT                ;Get boot and fat again to
  1378.                JC      LILLY_ERR               ; make sure not media switch.
  1379.                CALL    GET_FAT
  1380. LILLY_ERR:     JC      FAST_ERROR
  1381.  
  1382.                MOV     REREAD_FLAG,1
  1383.                LES     DI,SOURCE_POINTER       ;Find source dot dot entry.
  1384.                MOV     DX,ES:TREE_CLUSTER[DI]
  1385.                MOV     BX,OFFSET DOT_DOT
  1386.                MOV     DIR_LEN,2
  1387.                CALL    FIND_DIR
  1388.                JC      LOGICAL_ERR
  1389.  
  1390.                MOV     AX,ES:DIR_CLUSTER[DI]   ;Save old starting cluster.
  1391.                MOV     OLD_PARENT,AX
  1392.                LDS     SI,DEST_POINTER
  1393.                MOV     AX,TREE_CLUSTER[SI]
  1394.                PUSH    CS
  1395.                POP     DS
  1396.                MOV     NEW_PARENT,AX
  1397.                MOV     ES:DIR_CLUSTER[DI],AX   ;Change to new parent.
  1398.                CALL    WRITE_SECTOR
  1399.  
  1400.                CALL    MAKE_SOURCE             ;Make source dir name into a
  1401.                MOV     DX,OLD_PARENT           ; directory entry record type
  1402.                MOV     BX,OFFSET SOURCE_RECORD ;Find it.
  1403.                MOV     DIR_LEN,11
  1404.                CALL    FIND_DIR
  1405.                JC      FAST_ERROR
  1406.                CALL    SAVE_SOURCE             ;Save the directory entry.
  1407.                MOV     ES:DIR_NAME[DI],0E5H    ;Delete existing.
  1408.                CALL    WRITE_SECTOR
  1409.  
  1410.                MOV     DX,NEW_PARENT           ;Find an erased entry (our
  1411.                MOV     BX,OFFSET E5            ; temporary we created above.)
  1412.                MOV     DIR_LEN,1
  1413.                CALL    FIND_DIR
  1414.                JC      FAST_ERROR
  1415.                MOV     SI,OFFSET SOURCE_RECORD ;Place directory entry in it's
  1416.                MOV     CX,SIZE DIR_ENTRY       ; place.
  1417.                REP     MOVSB
  1418.                CALL    WRITE_SECTOR
  1419.                CLC
  1420.  
  1421. FAST_END:      RET
  1422.  
  1423. ANCESTOR_ERR:  POP     SI
  1424. FAST_ERROR:    MOV     SI,OFFSET ILLOGICAL_MSG
  1425. FAST_ERROR2:   PUSH    CS
  1426.                POP     DS
  1427.                CALL    DISPLAY_ERROR
  1428.                RET
  1429.  
  1430. LOGICAL_ERR:   MOV     SI,OFFSET LOGICAL_MSG
  1431.                JMP     FAST_ERROR2
  1432.  
  1433. ;----------------------------------------------;
  1434. DELETE:        PUSH    CS
  1435.                POP     DS
  1436.                CALL    CLEAR_MENU
  1437.                MOV     SI,OFFSET DELETE_MSG
  1438.                CALL    WRITE_STRING
  1439.                MOV     REREAD_FLAG,1
  1440.  
  1441.                LDS     SI,CS:SOURCE_POINTER
  1442.                CALL    SELECT_DIR
  1443.                JC      DELETE_END
  1444.                CALL    GET_NAME
  1445.                JMP     SHORT FIND_TOP
  1446.  
  1447. DO_DELETE:     MOV     DX,SI                   ;Change to next subdir.
  1448.                CALL    CHANGE_DIR
  1449.  
  1450. FIND_TOP:      PUSH    DS
  1451.                PUSH    SI
  1452.                ADD     SI,SIZE TREE
  1453. NEXT_TOP:      CMP     BYTE PTR [SI + 1],"─"   ;Is there a branch?
  1454.                JNZ     DO_FILES
  1455.                INC     SI
  1456.                INC     SI
  1457.                CALL    DO_DELETE               ;If yes, delete branch also.
  1458.                JC      DELETE_DONE
  1459.                DEC     SI
  1460.                DEC     SI
  1461.                JMP     NEXT_TOP
  1462.  
  1463. DO_FILES:      MOV     AX,CS
  1464.                MOV     DS,AX
  1465.                MOV     DX,OFFSET STAR_DOT_STAR ;Find all files.
  1466.                MOV     CX,1 OR 2               ;Hidden, read-only and normal.
  1467.                MOV     AH,4EH
  1468.                INT     21H
  1469.                JC      REMOVE_SUBDIR
  1470.                JMP     SHORT CK_ATTR
  1471.  
  1472. NEXT_DELETE:   MOV     AH,4FH
  1473.                INT     21H
  1474.                JC      REMOVE_SUBDIR
  1475.  
  1476. CK_ATTR:       MOV     DX,DTA.FILE_NAME
  1477.                TEST    DS:[DTA.ATTRIBUTE],1 OR 2
  1478.                JZ      DELETE_FILE
  1479.                XOR     CX,CX
  1480.                MOV     AX,4301H                ;Make normal attribute if
  1481.                INT     21H                     ; not already so can be deleted.
  1482.                JC      DELETE_DONE
  1483.  
  1484. DELETE_FILE:   MOV     AH,41H                  ;Delete file.
  1485.                INT     21H
  1486.                JC      DELETE_DONE
  1487.                JMP     NEXT_DELETE
  1488.  
  1489. REMOVE_SUBDIR: MOV     DX,OFFSET DOT_DOT       ;Return to parent directory.
  1490.                CALL    CHANGE_DIR              ;(Can't remove a directory
  1491.                POP     DX                      ; while logged onto the
  1492.                POP     DS                      ; directory.)
  1493.                MOV     CX,10H OR 2             ;Is directory hidden?
  1494.                MOV     AH,4EH
  1495.                INT     21H
  1496.                JC      DELETE_END
  1497.                TEST    CS:[DTA.ATTRIBUTE],2
  1498.                JZ      REMOVE_IT
  1499.                XOR     CX,CX
  1500.                MOV     AX,4301H                ;If yes, make normal.
  1501.                INT     21H
  1502.  
  1503. REMOVE_IT:     MOV     AH,3AH                  ;Remove subdirectory.
  1504.                INT     21H
  1505.                JMP     SHORT DELETE_END
  1506.  
  1507. DELETE_DONE:   POP     DX
  1508.                POP     DS
  1509. DELETE_END:    RET
  1510.  
  1511. ;----------------------------------------------;
  1512. ; OUTPUT: CF=1 if can't create subdirectory.
  1513.  
  1514. CREATE_TEMP:   MOV     DX,OFFSET TEMP
  1515.                MOV     AH,39H                  ;Create subdirectory.
  1516.                INT     21H
  1517.                JC      TEMP_END
  1518. REMOVE_DIR:    MOV     AH,3AH                  ;Remove subdirectory.
  1519.                INT     21H
  1520.                CALL    DISK_FREE               ;Update disk stats.
  1521. TEMP_END:      MOV     SI,OFFSET SUBDIR_MSG
  1522.                RET
  1523.  
  1524. ;----------------------------------------------;
  1525. ; INPUT:  DS:SI -> Source; DX = Sibling bar.
  1526. ; OUTPUT: DS:SI -> Parent; DX = Parent bar.
  1527.  
  1528. FIND_PARENT:   DEC     SI
  1529.                DEC     SI
  1530. NEXT_PARENT:   SUB     SI,SIZE TREE
  1531.                DEC     DX
  1532.                CMP     SI,1
  1533.                JZ      PARENT_END
  1534.                CMP     BYTE PTR [SI],"│"
  1535.                JZ      NEXT_PARENT
  1536.                CMP     BYTE PTR [SI],"├"
  1537.                JZ      NEXT_PARENT
  1538. PARENT_END:    RET
  1539.  
  1540. ;----------------------------------------------;
  1541. ; OUTPUT: CF=1 if dest dir has a subdir or file with name same as source dir.
  1542.  
  1543. CK_DUPLICATE:  PUSH    DS
  1544.                CALL    DOS_CURSOR
  1545.                MOV     DL,CS:TREE_DRIVE[BP]
  1546.                CALL    SELECT_DISK
  1547.                LDS     SI,CS:DEST_POINTER      ;Log on to destination.
  1548.                CALL    SELECT_DIR
  1549.                MOV     SI,OFFSET LOGICAL_MSG
  1550.                JC      DUP_ERR
  1551.                LDS     SI,CS:SOURCE_POINTER    ;Source name.
  1552.                CALL    GET_NAME
  1553.                MOV     DX,SI
  1554.                MOV     CX,10H OR 3             ;Subdir, hidden, read-only
  1555.                MOV     AH,4EH                  ; or normal.
  1556.                INT     21H                     ;Does it already exist?
  1557.                CMC
  1558.                JNC     DUP_END
  1559.  
  1560.                MOV     SI,OFFSET DUPLICATE_MSG
  1561. DUP_ERR:       CALL    FAST_ERROR2
  1562.                STC
  1563.  
  1564. DUP_END:       POP     DS
  1565.                RET
  1566.  
  1567. ;----------------------------------------------;
  1568. ; INPUT: DS:SI -> Record start.  OUTPUT: DS:SI -> Directory name.
  1569.  
  1570. GET_NAME:      OR      SI,SI                   ;Root?
  1571.                JZ      GET_NAME_END
  1572. NEXT_NAME:     LODSB
  1573.                CMP     AL,"─"
  1574.                JNZ     NEXT_NAME
  1575. GET_NAME_END:  RET
  1576.  
  1577. ;----------------------------------------------;
  1578.  
  1579. DISPLAY_MARK:  PUSH    DS
  1580.                MOV     AX,BAR_LINE[BP]
  1581.                MOV     SOURCE_BAR,AX
  1582.                MOV     CX,SIZE TREE
  1583.                MUL     CX
  1584.                MOV     DI,AX
  1585.                MOV     SOURCE_LINE,DI
  1586.                MOV     AX,TREE_SEG[BP]
  1587.                MOV     MARK_SEG,AX
  1588.                MOV     DS,AX
  1589.                MOV     MARK[DI],LITTLE_ARROW   ;Mark selected line with
  1590.                POP     DS                      ; a little arrow.
  1591.                CALL    DISPLAY_TREE
  1592.                RET
  1593.  
  1594. ERASE_MARK:    PUSH    DS
  1595.                LDS     DI,SOURCE_POINTER
  1596.                XOR     AL,AL
  1597.                OR      DI,DI
  1598.                JNZ     REMOVE_ARROW
  1599.                MOV     AL,"\"
  1600. REMOVE_ARROW:  MOV     MARK[DI],AL             ;Remove little arrow.
  1601.                POP     DS
  1602.                RET
  1603.  
  1604. ;----------------------------------------------;
  1605. ; INPUT:  DX = Starting cluster; DS:BX -> Dirname to find; DIR_LEN = length.
  1606. ; OUTPUT: ES:DI -> matching record; DX = Sector; CF=1 if failed.
  1607.  
  1608. FIND_DIR:      MOV     AX,CLUSTER_SEG
  1609.                MOV     ES,AX
  1610.                OR      DX,DX                   ;Special case if root.
  1611.                JZ      FIND_ROOT
  1612.  
  1613. NEXT_SOURCE:   MOV     LAST_CLUSTER,DX
  1614.                MOV     AX,DX
  1615.                DEC     AX
  1616.                DEC     AX
  1617.                MOV     CL,BPB_SectorsPerCluster
  1618.                XOR     CH,CH
  1619.                MUL     CX
  1620.                ADD     AX,DATA_SECTOR
  1621.                ADC     DX,0
  1622.                MOV     STARTING_SECTOR[2],DX
  1623.                MOV     DX,AX
  1624.  
  1625. NEXT_SECTOR2:  PUSH    CX
  1626.                CALL    FIND                    ;Find the record.
  1627.                POP     CX
  1628.                JNC     FIND_DIR_END
  1629.                ADD     DX,1                    ;Next sector.
  1630.                ADC     STARTING_SECTOR[2],0
  1631.                LOOP    NEXT_SECTOR2
  1632.  
  1633.                CALL    CK_FAT
  1634.                JNC     NEXT_SOURCE
  1635. FIND_DIR_END:  RET
  1636.  
  1637. ;----------------------------------------------;
  1638. ; Special case for root dirs.
  1639.  
  1640. FIND_ROOT:     MOV     DX,ROOT_SECTOR          ;Root sector is below
  1641.                MOV     CX,ROOT_SECTORS         ; data sectors.
  1642.                MOV     STARTING_SECTOR[2],0
  1643.  
  1644. NEXT_ROOT2:    PUSH    CX
  1645.                CALL    FIND
  1646.                POP     CX
  1647.                JNC     ROOT_END
  1648.                INC     DX
  1649.                LOOP    NEXT_ROOT2
  1650.                STC
  1651. ROOT_END:      RET
  1652.  
  1653. ;----------------------------------------------;
  1654. ; INPUT: ES -> Cluster seg; DS:BX -> Dirname to find;
  1655. ;        DX = Sector; DIR_LEN = length.
  1656. ; OUTPUT: CF=0 If found; Else, DX = Next sector.
  1657.  
  1658. FIND:          PUSH    BX
  1659.                XOR     BX,BX
  1660.                MOV     CX,1
  1661.                MOV     AX,CLUSTER_SEG
  1662.                MOV     TRANSFER_ADDRESS[2],AX
  1663.                MOV     DS,AX
  1664.                CALL    READ_DISK               ;Read the sector.
  1665.                PUSH    CS
  1666.                POP     DS
  1667.                POP     BX
  1668.                JC      FIND_DONE
  1669.  
  1670.                XOR     DI,DI
  1671.                MOV     CX,SECTOR_RECORDS       ;Records per sector.
  1672.                JMP     SHORT FIRST_TEMP
  1673. NEXT_TEMP:     ADD     DI,SIZE DIR_ENTRY       ;Next entry.
  1674. FIRST_TEMP:    PUSH    CX
  1675.                PUSH    DI
  1676.                MOV     SI,BX
  1677.                MOV     CX,DIR_LEN
  1678.                REPZ    CMPSB                   ;Is it a match?
  1679.                POP     DI
  1680.                POP     CX
  1681.                JNZ     FIND_TEMP
  1682.                TEST    ES:DIR_ATTR[DI],10H     ;Is it a subdir?
  1683.                CLC
  1684.                JNZ     FIND_END
  1685. FIND_TEMP:     LOOP    NEXT_TEMP
  1686. FIND_DONE:     STC
  1687. FIND_END:      RET
  1688.  
  1689. ;----------------------------------------------;
  1690.  
  1691. MAKE_SOURCE:   PUSH    DS
  1692.                LDS     SI,SOURCE_POINTER
  1693.                CALL    GET_NAME
  1694.                PUSH    CS
  1695.                POP     ES
  1696.                MOV     DI,OFFSET SOURCE_RECORD ;Store name in directory
  1697.                MOV     CX,8                    ;entry format that removes
  1698. NEXT_MAKE:     LODSB                           ; the delimiting dot
  1699.                CMP     AL,"."                  ; and pads with spaces.
  1700.                JZ      EXT2
  1701.                OR      AL,AL
  1702.                JZ      EXT1
  1703.                STOSB
  1704.                LOOP    NEXT_MAKE
  1705.                CMP     BYTE PTR [SI],"."
  1706.                JNZ     EXT2
  1707.                INC     SI
  1708.                JMP     SHORT EXT2
  1709.  
  1710. EXT1:          DEC     SI
  1711. EXT2:          MOV     AL,SPACE
  1712.                REP     STOSB
  1713.  
  1714.                MOV     CX,3
  1715. NEXT_EXT:      LODSB
  1716.                OR      AL,AL
  1717.                JZ      EXT_DONE
  1718.                STOSB
  1719.                LOOP    NEXT_EXT
  1720.  
  1721. EXT_DONE:      MOV     AL,SPACE
  1722.                REP     STOSB
  1723.                POP     DS
  1724.                RET
  1725.  
  1726. ;----------------------------------------------;
  1727. ; INPUT: ES:DI -> Source directory entry.
  1728.  
  1729. SAVE_SOURCE:   PUSH    DS                      ;Save directory record.
  1730.                PUSH    ES
  1731.                PUSH    DI
  1732.                MOV     AX,ES
  1733.                MOV     DS,AX
  1734.                MOV     SI,DI
  1735.                MOV     DI,OFFSET SOURCE_RECORD
  1736.                PUSH    CS
  1737.                POP     ES
  1738.                MOV     CX,SIZE DIR_ENTRY
  1739.                REP     MOVSB
  1740.                POP     DI
  1741.                POP     ES
  1742.                POP     DS
  1743.                RET
  1744.  
  1745. ;----------------------------------------------;
  1746. ; INPUT: SI -> Message.
  1747.  
  1748. DISPLAY_ERROR: CALL    CLEAR_MENU
  1749.                CALL    WRITE_STRING
  1750.                MOV     SI,OFFSET ANYKEY_MSG
  1751.                CALL    WRITE_STRING
  1752.                CALL    BEEP
  1753.                CALL    HIDE_CURSOR
  1754.                CALL    CLEAR_KEY
  1755.                CALL    GET_KEY                 ;Pause.
  1756.                CALL    DISPLAY_MENU
  1757.                STC
  1758.                RET
  1759.  
  1760. ;----------------------------------------------;
  1761. ; OUTPUT: DI -> Start of window; BH=Menu color.
  1762.  
  1763. CLEAR_MENU:    MOV     AL,ROWS
  1764.                DEC     AL                      ;Menu row.
  1765.                MOV     DH,AL
  1766.                MOV     CH,AL
  1767.                XOR     CL,CL
  1768.                MOV     DL,79                   ;Menu width.
  1769.                PUSH    AX
  1770.                MOV     BH,COLOR.C              ;Error color.
  1771.                CALL    DO_CLEAR
  1772.                POP     AX
  1773.                XOR     AH,AH
  1774.                CALL    CALC_ADDR
  1775.                RET
  1776.  
  1777. ;----------------------------------------------;
  1778. ; INPUT: BP=Tree Index; AX=DIR_COUNT; CX=BAR_LINE; DX=LISTING_TOP
  1779. ;        DI=Listing Bottom; SI=Listing Length
  1780.  
  1781. UP:            MOV     BX,-1                   ;Up a line.
  1782.                JMP     SHORT DO_ARROW
  1783.  
  1784. DOWN:          MOV     BX,1                    ;Down a line.
  1785. DO_ARROW:      ADD     CX,BX
  1786. CK_ARROW1:     OR      CX,CX
  1787.                JNS     CK_ARROW2
  1788.                XOR     CX,CX
  1789. CK_ARROW2:     CMP     CX,AX
  1790.                JBE     CK_PAGE
  1791.                MOV     CX,AX
  1792. CK_PAGE:       CMP     CX,DX
  1793.                JB      ADJUST_PAGE
  1794.                CMP     CX,DI
  1795.                JBE     NAVIGATE_DONE
  1796. ADJUST_PAGE:   ADD     DX,BX
  1797.                JMP     SHORT NAVIGATE_DONE
  1798.  
  1799. PGUP:          NEG     SI                      ;Up a page
  1800.  
  1801. PGDN:          ADD     CX,SI                   ;Down a page.
  1802.                ADD     DX,SI
  1803.                JNS     CK_PGDN
  1804.                XOR     DX,DX
  1805. CK_PGDN:       XOR     BX,BX
  1806.                CMP     DX,AX
  1807.                JBE     CK_ARROW1
  1808.                SUB     DX,SI
  1809.                JMP     CK_ARROW1
  1810.  
  1811. HOME:          XOR     CX,CX                   ;Home
  1812.                XOR     DX,DX
  1813.                JMP     SHORT NAVIGATE_DONE
  1814.  
  1815. END_KEY:       MOV     CX,AX                   ;End.
  1816.                DEC     SI
  1817.                SUB     DI,SI
  1818.                CMP     DI,DX
  1819.                JB      NAVIGATE_DONE
  1820.                MOV     DX,AX
  1821.                SUB     DX,SI
  1822.                JNS     NAVIGATE_DONE
  1823.                XOR     DX,DX
  1824.  
  1825. NAVIGATE_DONE: MOV     BAR_LINE[BP],CX
  1826.                MOV     LISTING_TOP[BP],DX
  1827.                CALL    DISPLAY_TREE
  1828. NAVIGATE_END:  RET
  1829.  
  1830. ;----------------------------------------------;
  1831.  
  1832. TAB_KEY:       XOR     ACTIVE_TREE,2
  1833.                JMP     SHORT CHANGE_TREE
  1834.  
  1835. LEFT:          MOV     ACTIVE_TREE,0
  1836.                JMP     SHORT CHANGE_TREE
  1837.  
  1838. RIGHT:         MOV     ACTIVE_TREE,2
  1839.  
  1840. CHANGE_TREE:   MOV     BP,ACTIVE_TREE
  1841.                XOR     BP,2
  1842.                CALL    DISPLAY_DRIVE
  1843.                XOR     BP,2
  1844.                CALL    DISPLAY_DRIVE
  1845.                RET
  1846. ;----------------------------------------------;
  1847. ; INPUT: BP = Tree Index.  OUTPUT: CF = 0 if successful.
  1848.  
  1849. READ_DRIVE:    CALL    DOS_CURSOR
  1850.                MOV     DL,TREE_DRIVE[BP]       ;Retrieve drive.
  1851.                INC     DL                      ;Adjust.
  1852.                MOV     AH,32H                  ;Retrieve Disk Block.
  1853.                INT     21H
  1854.                MOV     DH,[BX]                 ;BIOS disk block drive no.
  1855.                PUSH    CS
  1856.                POP     DS
  1857.                OR      AL,AL                   ;Does disk request exist?
  1858.                JZ      EXISTS
  1859.  
  1860. READ_ERROR:    PUSH    CS
  1861.                POP     ES
  1862.                STC
  1863.                RET
  1864.  
  1865. EXISTS:        DEC     DL
  1866.                CMP     DL,DH                   ;Substitued?
  1867.                JNZ     READ_ERROR
  1868.                CALL    GET_BOOT
  1869.                JC      READ_ERROR
  1870.  
  1871.                MOV     SI,OFFSET UNNAMED
  1872.                MOV     DI,VOLUME_NAME[BP]
  1873.                MOV     CX,VOLUME_LEN
  1874.                REP     MOVSB
  1875.                CALL    GET_ROOT
  1876.                JZ      READ_END                ;If none, done here.
  1877.                CALL    GET_FAT
  1878.                JNC     GET_SUBS
  1879.                JMP     READ_ERROR
  1880.  
  1881. ;----------------------------------------------;
  1882. ; INPUT: BX = Root directory entries.
  1883.  
  1884. GET_SUBS:      XOR     SI,SI
  1885. UP_LEVEL:      MOV     CX,BX                   ;Retrieve record count.
  1886.                ADD     TREE_LEVEL,2            ;Bump point to next level.
  1887.                MOV     BX,TREE_LEVEL
  1888.                MOV     [WORD PTR LEVEL_ADDRESS + BX],DI ;Save level address.
  1889.                XOR     BX,BX                   ;Zero out entry counter.
  1890. NEXT_SECTOR:   MOV     DX,ES:CLUSTER[SI]       ;Retrieve starting cluster.
  1891.  
  1892. NEXT_CLUSTER:  MOV     LAST_CLUSTER,DX         ;And save.
  1893.                PUSH    CX                      ;Save some registers.
  1894.                PUSH    BX
  1895.                CALL    READ_CLUSTER            ;Retrieve directory sector.
  1896.                POP     BX
  1897.                MOV     DX,ES:ENTRY[SI]        ;Retrieve parent entry number.
  1898.                PUSH    SI
  1899.                MOV     CX,CLUST_RECORDS        ;Retrieve records per cluster.
  1900.                CALL    STORE_RECORD            ;Store subdirectories.
  1901.                POP     SI
  1902.                POP     CX
  1903.                JC      END_LEVEL               ;If carry, last entry found.
  1904.                CALL    CK_FAT                  ;Else, get next cluster.
  1905.                JNC     NEXT_CLUSTER            ;If carry, last cluster found.
  1906.  
  1907. END_LEVEL:     ADD     SI,SIZE TREE_DATA       ;Else, point to next root entry.
  1908.                LOOP    NEXT_SECTOR             ;Find next subdirectory.
  1909.                CMP     SI,DI                   ;Did we find any at this level?
  1910.                JNZ     UP_LEVEL                ;If yes, continue.
  1911.                MOV     AX,0FFFFH               ;Else, done; mark with signature.
  1912.                STOSB
  1913.                MOV     BX,TREE_LEVEL
  1914.                MOV     [WORD PTR LEVEL_ADDRESS+BX+2],AX   ;Mark level address.
  1915.                CALL    SORT                               ;Alphabetize by level.
  1916.  
  1917. READ_END:      CALL    DISK_FREE               ;Get disk stats.
  1918.                JC      READ_DONE
  1919.                CALL    FORMAT                  ;Format into tree.
  1920.                CALL    CK_VARS
  1921.                PUSH    CS
  1922.                POP     ES
  1923.                CLC
  1924.  
  1925. READ_DONE:     RET
  1926.  
  1927. ;----------------------------------------------;
  1928. ; INPUT:  BP = Tree Index.
  1929. ; OUTPUT: BIG_DISK_FLAG=1 if >32 meg; CF=1 if failed.
  1930.  
  1931. GET_BOOT:      MOV     BIG_DISK_FLAG,0         ;Assume small disk (<32Meg.)
  1932. NEXT_BOOT:     PUSH    DS
  1933.                MOV     CX,1                    ;Retrieve one boot record.
  1934.                XOR     DX,DX                   ;Sector zero.
  1935.                MOV     STARTING_SECTOR[2],0    ;High half.
  1936.                XOR     BX,BX                   ;Offset zero transfer address.
  1937.                MOV     AX,CLUSTER_SEG
  1938.                MOV     TRANSFER_ADDRESS[2],AX
  1939.                MOV     DS,AX
  1940.                MOV     BYTE PTR [BX],0         ;Zero to detect bad read.
  1941.                CALL    READ_DISK
  1942.                POP     DS
  1943.                JNC     STORE_BOOT
  1944.                CMP     BIG_DISK_FLAG,1
  1945.                MOV     BIG_DISK_FLAG,1
  1946.                JNZ     NEXT_BOOT
  1947.                STC
  1948.                JMP     SHORT BOOT_END
  1949.  
  1950. STORE_BOOT:    MOV     DS,CLUSTER_SEG
  1951.                CMP     BYTE PTR DS:[0],0
  1952.                STC
  1953.                JZ      BOOT_END
  1954.                MOV     SI,11                   ;Start of BPB in boot record.
  1955.                MOV     DI,OFFSET BPB
  1956.                MOV     CX,BPB_LENGTH
  1957.                REP     MOVSB
  1958.  
  1959.                PUSH    CS
  1960.                POP     DS
  1961.                MOV     FAT_TYPE,FAT_16_BIT     ;12 or 16 bit FAT?
  1962.                MOV     CL,BPB_SectorsPerCluster
  1963.                XOR     CH,CH
  1964.                MOV     AX,BPB_TotalSectors
  1965.                OR      AX,AX
  1966.                JZ      GET_RECORDS
  1967.                XOR     DX,DX
  1968.                DIV     CX
  1969.                CMP     AX,4086
  1970.                JAE     GET_RECORDS
  1971.                MOV     FAT_TYPE,FAT_12_BIT
  1972.  
  1973. GET_RECORDS:   MOV     AX,BPB_BytesPerSector   ;Retrieve bytes per sector.
  1974.                XOR     DX,DX
  1975.                MOV     BX,SIZE DIR_ENTRY
  1976.                DIV     BX
  1977.                MOV     SECTOR_RECORDS,AX
  1978.                MUL     CX                      ;Times sector per cluster.
  1979.                MOV     CLUST_RECORDS,AX
  1980.  
  1981.                MOV     AX,BPB_RootEntries      ;Retrieve number of root entries.
  1982.                MUL     BX
  1983.                DIV     BPB_BytesPerSector      ;Divide by bytes per sector.
  1984.                MOV     ROOT_SECTORS,AX         ;That's root length in sectors.
  1985.  
  1986.                MOV     AX,BPB_ReservedSectors
  1987.                MOV     CL,BPB_NumberOfFats
  1988.                XOR     CH,CH
  1989. ADD_FATS:      ADD     AX,BPB_SectorsPerFat
  1990.                LOOP    ADD_FATS
  1991.  
  1992.                MOV     ROOT_SECTOR,AX
  1993.                ADD     AX,ROOT_SECTORS         ;AX = directory sectors.
  1994.                MOV     DATA_SECTOR,AX
  1995.  
  1996.                CLC
  1997.  
  1998. BOOT_END:      PUSH    CS
  1999.                POP     DS
  2000.                RET
  2001.  
  2002. ;----------------------------------------------;
  2003. ; OUTPUT: BX=Root directory entires; ZF=1 if none.
  2004.  
  2005. GET_ROOT:      MOV     ES,TREE_DATA_SEG[BP]
  2006.                XOR     DI,DI                     ;Point to database storage.
  2007.                MOV     BYTE PTR ES:[DI],0FFH     ;Initialize with end signature.
  2008.                MOV     WORD PTR LEVEL_ADDRESS,DI ;Store starting level address.
  2009.                XOR     BX,BX                     ;Entry number.
  2010.                MOV     TREE_LEVEL,BX             ;Tree level zero also.
  2011.                MOV     DX,ROOT_SECTOR
  2012.                MOV     CX,ROOT_SECTORS
  2013.  
  2014. NEXT_ROOT:     PUSH    CX
  2015.                PUSH    BX
  2016.                MOV     CX,1
  2017.                XOR     BX,BX                   ;Transfer address offset.
  2018.                MOV     STARTING_SECTOR[2],BX   ;High half is zero.
  2019.                MOV     AX,CLUSTER_SEG
  2020.                MOV     TRANSFER_ADDRESS[2],AX
  2021.                MOV     DS,AX
  2022.                CALL    READ_DISK
  2023.                PUSH    CS
  2024.                POP     DS
  2025.  
  2026.                POP     BX
  2027.                MOV     CX,SECTOR_RECORDS
  2028.                CALL    STORE_RECORD            ;Store them in database.
  2029.                POP     CX
  2030.                JC      GET_ROOT_END            ;Done when first 0 entry
  2031.                INC     DX                      ; encountered.
  2032.                LOOP    NEXT_ROOT
  2033. GET_ROOT_END:  OR      BX,BX                   ;BX returns with no. entries.
  2034.                RET
  2035.  
  2036. ;----------------------------------------------;
  2037. ; OUTPUT: CF = 1 if failed.  BX preserved.
  2038.  
  2039. GET_FAT:       PUSH    BX                      ;Save entry count.
  2040.                MOV     DX,BPB_ReservedSectors
  2041.                MOV     CX,BPB_SectorsPerFat
  2042.                MOV     BX,FAT_SEG
  2043.  
  2044. NEXT_FAT:      PUSH    BX
  2045.                PUSH    CX
  2046.                PUSH    DX
  2047.  
  2048.                MOV     STARTING_SECTOR[2],0    ;High half.
  2049.                MOV     TRANSFER_ADDRESS[2],BX
  2050.                MOV     DS,BX
  2051.                XOR     BX,BX
  2052.                MOV     CX,1
  2053.                CALL    READ_DISK
  2054.                PUSH    CS
  2055.                POP     DS
  2056.                JNC     FAT_OK
  2057.                ADD     SP,6
  2058.                STC
  2059.                JMP     SHORT FAT_END
  2060.  
  2061. FAT_OK:        POP     DX
  2062.                INC     DX
  2063.                MOV     AX,BPB_BytesPerSector
  2064.                MOV     CL,4
  2065.                SHR     AX,CL                   ;Paragraphs per sector.
  2066.                POP     CX
  2067.                POP     BX
  2068.                ADD     BX,AX
  2069.                LOOP    NEXT_FAT
  2070.                CLC
  2071.  
  2072. FAT_END:       POP     BX
  2073.                RET
  2074.  
  2075. ;----------------------------------------------;
  2076. ; INPUT:  CX = No. of Sectors; DX = Logical Sector; DS:BX -> Transfer Address.
  2077. ; OUTPUT: CF = 0 if successful; CF = 1 if failed.
  2078.  
  2079. READ_DISK:     mov     ah,0dh
  2080.                int     21h
  2081.                PUSH    BP                      ;Call destroys all registers
  2082.                PUSH    DX
  2083.                PUSH    SI                      ; except segment registers
  2084.                PUSH    DI                      ; so we have to preserve.
  2085.  
  2086.                MOV     AL,CS:TREE_DRIVE[BP]    ;Retrieve drive.
  2087.                CMP     CS:BIG_DISK_FLAG,0
  2088.                JZ      DIRECT_READ
  2089.                PUSH    CS
  2090.                POP     DS
  2091.                MOV     TRANSFER_ADDRESS[0],BX
  2092.                MOV     BX,OFFSET PACKET
  2093.                MOV     STARTING_SECTOR[0],DX
  2094.                MOV     NUMBER_OF_SECTORS,CX
  2095.                MOV     CX,-1
  2096.  
  2097. DIRECT_READ:   INT     25H                     ;Read the sectors.
  2098.                POP     AX                      ;Get rid off flags left on stack.
  2099.  
  2100.                POP     DI
  2101.                POP     SI
  2102.                POP     DX
  2103.                POP     BP
  2104.                mov     ah,0dh
  2105.                int     21h
  2106.                RET
  2107.  
  2108. ;----------------------------------------------;
  2109. ; INPUT:  DX = Logical Sector.
  2110. ; OUTPUT: CF = 0 if successful; CF = 1 if failed.
  2111.  
  2112. WRITE_SECTOR:  mov     ah,0dh
  2113.                int     21h
  2114.                PUSH    BP                      ;Call destroys all registers
  2115.                PUSH    DS
  2116.  
  2117.                XOR     BX,BX
  2118.                MOV     CX,1
  2119.                MOV     AL,TREE_DRIVE[BP]       ;Retrieve drive.
  2120.                CMP     BIG_DISK_FLAG,0
  2121.                MOV     DS,CLUSTER_SEG
  2122.                JZ      DIRECT_WRITE
  2123.  
  2124.                PUSH    CS
  2125.                POP     DS
  2126.                MOV     BX,OFFSET PACKET
  2127.                MOV     CX,-1
  2128.  
  2129. DIRECT_WRITE:  INT     26H                     ;Write the sector.
  2130.                POP     AX                      ;Get rid off flags left on stack.
  2131.  
  2132.                POP     DS
  2133.                POP     BP
  2134.                mov     ah,0dh
  2135.                int     21h
  2136.                RET
  2137.  
  2138. ;----------------------------------------------;
  2139.  
  2140. READ_CLUSTER:  PUSH    BX
  2141.                MOV     AX,LAST_CLUSTER         ;Retrieve cluster number.
  2142.                DEC     AX                      ;Subtract to reflect cluster
  2143.                DEC     AX                      ; 2 as first logical data sector.
  2144.                MOV     CL,BPB_SectorsPerCluster ;Retrieve sectors per cluster.
  2145.                XOR     CH,CH
  2146.                MUL     CX                       ;Multiply to get sector start.
  2147.  
  2148.                ADD     AX,DATA_SECTOR          ;Add start of first data cluster.
  2149.                ADC     DX,0
  2150.                MOV     STARTING_SECTOR[2],DX   ;High half.
  2151.                MOV     DX,AX
  2152.                XOR     BX,BX
  2153.                MOV     AX,CLUSTER_SEG
  2154.                MOV     TRANSFER_ADDRESS[2],AX
  2155.                MOV     DS,AX
  2156.                CALL    READ_DISK                ;And get data.
  2157.                PUSH    CS
  2158.                POP     DS
  2159.                POP     BX
  2160.                RET
  2161.  
  2162. ;------------------------------------------------------------------;
  2163. ; This subroutine stores the level number, entry number, parent    ;
  2164. ; entry number, the directory name and attribute byte in database. ;
  2165. ;------------------------------------------------------------------;
  2166. ; INPUT: CX=Directory records; BX=Level; DX=Parent; ES:DI -> Tree_data storage.
  2167.  
  2168. STORE_RECORD:  PUSH    DS
  2169.                XOR     SI,SI
  2170.                MOV     DS,CLUSTER_SEG
  2171. NEXT_RECORD:   CMP     BYTE PTR [SI],0         ;No more entries?
  2172.                JZ      STORE_RETURN            ;If yes, done here.
  2173.                TEST    DIR_ATTR[SI],8          ;Is it a volume label?
  2174.                JNZ     STORE_VOLUME
  2175.                TEST    DIR_ATTR[SI],10H        ;Is it a directory?
  2176.                JZ      LOOP_STORE              ;If no, next entry.
  2177.                CMP     DIR_NAME[SI],0E5H       ;Is it a removed directory?
  2178.                JZ      LOOP_STORE              ;If yes, skip.
  2179.                CMP     DIR_NAME[SI],"."        ;Is it a dot or dot-dot entry?
  2180.                JZ      LOOP_STORE              ;If yes, skip.
  2181.  
  2182.                PUSH    SI
  2183.                MOV     AX,CS:TREE_LEVEL        ;Store level number.
  2184.                STOSB
  2185.                MOV     AX,BX                   ;Store entry number.
  2186.                STOSW
  2187.                MOV     AX,DX                   ;Store parent entry number.
  2188.                STOSW
  2189.                PUSH    CX
  2190.                MOV     CX,11                   ;Store 11 bytes of name.
  2191.                REP     MOVSB
  2192.                POP     CX
  2193.                ADD     SI,15                   ;Store starting cluster.
  2194.                MOVSW
  2195.                INC     BX                      ;Increment entry count.
  2196.                POP     SI
  2197.                XOR     AX,AX                   ;Assume not a hidden directory.
  2198.                TEST    DIR_ATTR[SI],2          ;Is it hidden?
  2199.                JZ      STORE_ATTRIB            ;If no, store null.
  2200.                MOV     AX,"H"                  ;Else, store "H".
  2201. STORE_ATTRIB:  STOSW
  2202.  
  2203. LOOP_STORE:    ADD     SI,SIZE DIR_ENTRY       ;Point to next entry.
  2204.                LOOP    NEXT_RECORD
  2205.                POP     DS
  2206.                CLC                             ;Indicate full sector.
  2207.                RET
  2208.  
  2209. STORE_RETURN:  STC
  2210.                POP     DS
  2211.                RET
  2212.  
  2213.  
  2214. STORE_VOLUME:  CMP     DIR_NAME [SI],0E5H      ;Is it a removed volume?
  2215.                JZ      LOOP_STORE              ;If yes, skip.
  2216.                PUSH    SI
  2217.                PUSH    DI
  2218.                PUSH    ES
  2219.                PUSH    CX
  2220.  
  2221.                PUSH    CS
  2222.                POP     ES
  2223.                MOV     DI,CS:VOLUME_NAME[BP]
  2224.                MOV     CX,VOLUME_LEN
  2225.                REP     MOVSB
  2226.  
  2227.                POP     CX
  2228.                POP     ES
  2229.                POP     DI
  2230.                POP     SI
  2231.                JMP     LOOP_STORE
  2232.  
  2233. ;-------------------------------------------------------------------;
  2234. ; This subroutine finds the next cluster in the chain from the FAT. ;
  2235. ;-------------------------------------------------------------------;
  2236. ; OUTPUT: DX = Cluster; CF = 0 if not last cluster; CF = 1 if no more clusters.
  2237.  
  2238. CK_FAT:        PUSH    ES                      ;Save some registers.
  2239.                PUSH    BX
  2240.                PUSH    CX
  2241.  
  2242.                MOV     AX,LAST_CLUSTER         ;Retrieve last cluster.
  2243.                PUSH    AX                      ;Save.
  2244.                CMP     FAT_TYPE,FAT_16_BIT
  2245.                JZ      SIXTEEN_BIT
  2246. TWELVE_BIT:    MOV     BX,15                   ;Else, 12 bit FAT.
  2247.                MUL     BX                      ;Multiply by 1.5 (or 15/10).
  2248.                MOV     BX,10
  2249.                DIV     BX
  2250.                MOV     BX,AX
  2251.                MOV     ES,FAT_SEG
  2252.                MOV     DX,ES:[BX]              ;Retrieve cluster pointer.
  2253.                POP     AX                      ;Retrieve last cluster.
  2254.                TEST    AX,1                    ;Was last cluster even number?
  2255.                JZ      LOW_ORDER               ;If yes, use low order 12 bits.
  2256.                MOV     CL,4                    ;Else, high order 12 bits.
  2257.                SHR     DX,CL                   ;Shift right 4 bits.
  2258.                JMP     SHORT CK_12BIT
  2259. LOW_ORDER:     AND     DX,0000111111111111B    ;Mask off top 4 bits.
  2260. CK_12BIT:      CMP     DX,0FF8H                ;Is it end of chain?
  2261.                JAE     CLUSTER_END             ;If yes, indicate so.
  2262.                JMP     SHORT RETURN_CLUST      ;Else, return with cluster in DX.
  2263.  
  2264. SIXTEEN_BIT:   MOV     CL,3
  2265.                SHR     AX,CL
  2266.                MOV     BX,FAT_SEG
  2267.                ADD     BX,AX
  2268.                MOV     ES,BX
  2269.                POP     BX                      ;Retrieve last cluster.
  2270.                SHL     BX,1                    ;Multiply by 2.
  2271.                AND     BX,15
  2272.  
  2273.                MOV     DX,ES:[BX]              ;Retrieve next cluster number.
  2274.                CMP     DX,0FFF8H               ;Is it end of chain?
  2275.                JAE     CLUSTER_END             ;If yes, indicate so.
  2276.  
  2277. RETURN_CLUST:  POP     CX                      ;Restore registers.
  2278.                POP     BX
  2279.                POP     ES
  2280.                CLC                             ;Indicate not end of chain.
  2281.                RET
  2282.  
  2283. CLUSTER_END:   POP    CX
  2284.                POP    BX
  2285.                POP    ES
  2286.                STC                             ;Indicate end of cluster chain.
  2287.                RET
  2288.  
  2289. ;--------------------------------------------------------;
  2290. ; This subroutine alphabetizes the directories by level. ;
  2291. ;--------------------------------------------------------;
  2292.  
  2293. SORT:          PUSH    DS
  2294.                PUSH    BP
  2295.                PUSH    ES
  2296.                POP     DS
  2297.  
  2298.                XOR     BP,BP                             ;Zero in level pointer.
  2299. LEVEL_SORT:    MOV     DX,CS:[WORD PTR LEVEL_ADDRESS+BP+2] ;Level offset.
  2300.                CMP     DX,0FFFFH                           ;End signature?
  2301.                JZ      SORT_END                    ;If yes, done here.
  2302.                SUB     DX,SIZE TREE_DATA           ;Point to end of lower level.
  2303.                PUSH    BP                          ;Save level pointer.
  2304.  
  2305. NEXT_PASS:     POP     BP
  2306.                PUSH    BP
  2307.                MOV     BX,CS:[WORD PTR LEVEL_ADDRESS+BP]   ;Start of level.
  2308.                XOR     BP,BP                            ;Zero in exchange flag.
  2309.                CMP     BX,DX                            ;End of level?
  2310.                JZ      SORT_SET                         ;If yes, next level.
  2311.  
  2312. NEXT_SORT:     MOV     SI,BX                   ;Source and destination.
  2313.                ADD     SI,DIRECTORY            ;Point to name
  2314.                MOV     DI,BX                                   ; in each record.
  2315.                ADD     DI,SIZE TREE_DATA + DIRECTORY
  2316.                MOV     CX,SIZE DIRECTORY
  2317.                REPZ    CMPSB                   ;Compare names.
  2318.                JBE     END_SORT                ;If already in order, skip.
  2319.  
  2320.                MOV     SI,BX                   ;Else, recover pointers.
  2321.                MOV     DI,BX
  2322.                ADD     DI,SIZE TREE_DATA
  2323.                MOV     CX,SIZE TREE_DATA       ;Exchange the records.
  2324. NEXT_SWAP:     MOV     AL,[DI]
  2325.                MOVSB
  2326.                MOV     [SI-1],AL
  2327.                LOOP    NEXT_SWAP
  2328.                MOV     BP,1                    ;Flag that exchange was made.
  2329.  
  2330. END_SORT:      ADD     BX,SIZE TREE_DATA       ;Point to next record.
  2331.                CMP     BX,DX                   ;End of top?
  2332.                JB      NEXT_SORT               ;If no, bubble sort next.
  2333.                SUB     DX,SIZE TREE_DATA       ;Else, move top down one record.
  2334.                OR      BP,BP                   ;Was there exchange made?
  2335.                JNZ     NEXT_PASS
  2336.  
  2337. SORT_SET:      POP     BP
  2338.                INC     BP                      ;Next level.
  2339.                INC     BP
  2340.                JMP     LEVEL_SORT              ;Sort it.
  2341.  
  2342. SORT_END:      POP     BP
  2343.                POP     DS                      ;Restore data segment.
  2344.                RET
  2345.  
  2346. ;-------------------------------------------------------------;
  2347. ; This subroutine formats the database into a directory tree. ;
  2348. ;-------------------------------------------------------------;
  2349.  
  2350. FORMAT:        PUSH    BP
  2351.                PUSH    DS
  2352.                MOV     ES,TREE_SEG[BP]
  2353.  
  2354. STORE_ROOT:    XOR     AX,AX
  2355.                XOR     DI,DI
  2356.                MOV     CX,SIZE TREE * MAX_ENTRIES
  2357.                SHR     CX,1
  2358.                REP     STOSW
  2359.                ADC     CX,CX
  2360.                REP     STOSB
  2361.  
  2362.                XOR     DI,DI
  2363.                MOV     SI,OFFSET ROOT
  2364.                MOV     CX,ROOT_LEN
  2365.                REP     MOVSB
  2366.                MOV     DIRS,1
  2367.  
  2368.                MOV     DI,SIZE TREE            ;Point to storage.
  2369.                MOV     LAST_ENTRY,DI           ;Save current entry.
  2370.                MOV     DS,TREE_DATA_SEG[BP]
  2371.                XOR     BP,BP                   ;Zero in level pointer.
  2372.                XOR     SI,SI
  2373.                CMP     BYTE PTR [SI],0FFH      ;No subs signature?
  2374.                JZ      SKIP_FORMAT             ;If yes, skip format.
  2375.                MOV     CS:BRANCH_NUM,0
  2376.  
  2377. NEXT_FORMAT:   INC     CS:BRANCH_NUM
  2378.                CALL    STORE_NAME              ;Format the directory name.
  2379.                ADD     SI,SIZE TREE_DATA       ;Point to next record.
  2380.                CMP     BYTE PTR [SI],0         ;End of root directory?
  2381.                JZ      NEXT_FORMAT             ;If no, get next entry.
  2382.  
  2383. SKIP_FORMAT:   MOV     AX,0FFH
  2384.                STOSW
  2385.                POP     DS
  2386.                POP     BP
  2387.                MOV     AX,DIRS                ;Retrieve directory count.
  2388.                MOV     DIR_COUNT[BP],AX
  2389. FORMAT_END:    RET
  2390.  
  2391. ;-----------------------------------------------------------;
  2392. ; This subroutine recursively builds the subdirectory tree. ;
  2393. ;-----------------------------------------------------------;
  2394. ; INPUT: DS:SI -> Tree_Data; BP = Tree level; ES:DI -> Tree storage.
  2395.  
  2396. STORE_NAME:    PUSH    SI                      ;Save a couple registers.
  2397.                PUSH    BP
  2398.  
  2399.                PUSH    DI                      ;Save pointers.
  2400.                PUSH    SI
  2401.                PUSH    SI
  2402.                MOV     SI,CS:LAST_ENTRY        ;Retrieve last entry.
  2403.                MOV     DX,DI                   ;Retrieve current position.
  2404.                CMP     SI,DX                   ;Have stored any subdirectories?
  2405.                JZ      STORE_DIR               ;If no, skip tree structuring.
  2406.                MOV     BYTE PTR ES:BRANCH[SI+BP],"├"
  2407. PLACE_BAR:     ADD     SI,SIZE TREE            ;Move to next record.
  2408.                CMP     SI,DX                   ;Are we at the current record?
  2409.                JZ      STORE_DIR               ;If yes, done here.
  2410.                MOV     BYTE PTR ES:BRANCH[SI+BP],"│"
  2411.                JMP     SHORT PLACE_BAR         ;Repeat until up to date.
  2412.  
  2413. STORE_DIR:     MOV     CS:LAST_ENTRY,SI        ;Store current position.
  2414.                POP     SI                      ;Restore current record pointer.
  2415.                INC     CS:DIRS                 ;Increment directory counter.
  2416.                ADD     DI,BP                   ;Add level pointer.
  2417.                INC     DI                      ;Pointer past mark.
  2418.                MOV     AL,"└"                  ;Store L line character.
  2419.                STOSB
  2420.                MOV     AL,"─"                  ;Store horizontal line character.
  2421.                STOSB
  2422.                ADD     SI,DIRECTORY            ;Point to name.
  2423.                MOV     CX,8
  2424.                CALL    STORE_BYTES             ;And store in tree.
  2425.                CMP     BYTE PTR [SI],SPACE
  2426.                JZ      END_NAME
  2427.                MOV     AL,"."                  ;If exists, append extension.
  2428.                STOSB
  2429.                MOV     CX,3
  2430.                CALL    STORE_BYTES
  2431. END_NAME:      POP     SI                      ;Restore current record pointer.
  2432.                INC     DI                      ;Bump pointer for space.
  2433.                MOV     AX,ATTRIB[SI]           ;Retrieve "hidden" field.
  2434.                STOSB                           ;And store it.
  2435. NEXT_DEST:     POP     DI                      ;Restore destination pointer.
  2436.                MOV     AX,CLUSTER[SI]          ;Dir starting cluster.
  2437.                MOV     ES:TREE_CLUSTER[DI],AX
  2438.                MOV     AX,CS:BRANCH_NUM
  2439.                MOV     ES:BRANCH_NO[DI],AX
  2440.                ADD     DI,SIZE TREE            ;Point to next tree record.
  2441.  
  2442.                PUSH    CS:LAST_ENTRY           ;Save current position pointer.
  2443.                MOV     CS:LAST_ENTRY,DI        ;Save our current position.
  2444.                INC     BP                      ;Bump pointer to next level.
  2445.                INC     BP
  2446.                MOV     BX,CS:[WORD PTR LEVEL_ADDRESS+BP] ;Get level offset.
  2447.  
  2448. NEXT_SUB:      MOV     AL,LEVEL[BX]            ;Retrieve level pointer.
  2449.                XOR     AH,AH
  2450.                CMP     AX,BP                   ;Is it our level?
  2451.                JA      STORE_END               ;If next level, done here.
  2452.                MOV     AX,PARENT[BX]           ;Retrieve parent entry number.
  2453.                CMP     AX,ENTRY[SI]            ;Is it our entry number?
  2454.                JNZ     SKIP_SUB                ;If no, check next record.
  2455.  
  2456. GET_SUB:       PUSH    BX                      ;Else, save pointers.
  2457.                PUSH    SI
  2458.                MOV     SI,BX                   ;Point to our offset.
  2459.                CALL    STORE_NAME              ;Store subdirectory.
  2460.                POP     SI                      ;Restore pointers.
  2461.                POP     BX
  2462.  
  2463. SKIP_SUB:      ADD     BX,SIZE TREE_DATA       ;Next record.
  2464.                JMP     SHORT NEXT_SUB
  2465.  
  2466. STORE_END:     POP     CS:LAST_ENTRY           ;Restore last entry pointer.
  2467.                POP     BP
  2468.                POP     SI
  2469.                RET
  2470.  
  2471. ;----------------------------------------------;
  2472. ; Add logic to store spaces after first non-space char.
  2473.  
  2474. STORE_BYTES:   LODSB                           ;Store all non space name
  2475.                CMP     AL,SPACE                ; characters.
  2476.                JZ      SKIP_STORE
  2477.                STOSB
  2478. SKIP_STORE:    LOOP    STORE_BYTES
  2479.                RET
  2480.  
  2481. ;----------------------------------------------;
  2482. ; INPUT: BP = Tree Index
  2483.  
  2484. DISPLAY_TREE:  CALL    SETUP_COLOR
  2485.                PUSH    DS
  2486.                PUSH    BP
  2487.                MOV     AX,LISTING_TOP[BP]
  2488.                MOV     CX,SIZE TREE
  2489.                MUL     CX
  2490.                MOV     SI,AX
  2491.  
  2492.                MOV     AX,2
  2493.                CALL    CALC_COL
  2494.  
  2495.                MOV     DX,LISTING_TOP[BP]
  2496.                MOV     BH,TREE_COLOR
  2497.                MOV     CX,LISTING_LEN
  2498.                CMP     BP,ACTIVE_TREE
  2499.                MOV     DS,TREE_SEG[BP]
  2500.                MOV     BP,CS:BAR_LINE[BP]
  2501.                JZ      NEXT_DISPLAY
  2502.                MOV     BP,-1                   ;Turn off highlight bar.
  2503.  
  2504. NEXT_DISPLAY:  PUSH    CX
  2505.                PUSH    DX
  2506.                PUSH    SI
  2507.                PUSH    DI
  2508.                MOV     CX,SIZE MARK + SIZE BRANCH
  2509.                CMP     DX,BP
  2510.                JNZ     NEXT_DISP1
  2511.  
  2512.                OR      DX,DX                   ;Is it the root?
  2513.                JZ      HIGHLIGHT
  2514. BAR:           LODSB
  2515.                DEC     CX
  2516.                CALL    WRITE_SCREEN
  2517.                CMP     BL,"─"
  2518.                JNZ     BAR
  2519.  
  2520. HIGHLIGHT:     MOV     BH,CS:COLOR.C
  2521. NEXT_HIGH:     LODSB
  2522.                OR      AL,AL
  2523.                JZ      BAR_END
  2524.                CALL    WRITE_SCREEN
  2525.                LOOP    NEXT_HIGH
  2526.                JMP     SHORT LOOP_DISPLAY
  2527.  
  2528. BAR_END:       MOV     BH,CS:TREE_COLOR
  2529.                DEC     SI
  2530. NEXT_BAR_END:  LODSB
  2531.                CALL    WRITE_SCREEN
  2532.                LOOP    NEXT_BAR_END
  2533.                JMP     SHORT LOOP_DISPLAY
  2534.  
  2535.  
  2536. NEXT_DISP1:    LODSB
  2537.                CALL    WRITE_SCREEN
  2538.                LOOP    NEXT_DISP1
  2539.  
  2540. LOOP_DISPLAY:  POP     DI
  2541.                ADD     DI,CS:CRT_WIDTH
  2542.                POP     SI
  2543.                ADD     SI,SIZE TREE
  2544.                POP     DX
  2545.                INC     DX
  2546.                POP     CX
  2547.                LOOP    NEXT_DISPLAY
  2548.                POP     BP
  2549.                POP     DS
  2550.                RET
  2551.  
  2552. ;----------------------------------------------;
  2553. ; INPUT: BP = Tree Index
  2554.  
  2555. DISPLAY_DRIVE: CALL    SETUP_COLOR
  2556.                MOV     AL,TREE_DRIVE[BP]
  2557.                ADD     AL,"A"
  2558.                MOV     DRIVE_LETTER,AL
  2559.  
  2560.                MOV     AX,1
  2561.                CALL    CALC_COL
  2562.                MOV     BH,TREE_COLOR
  2563.                MOV     SI,OFFSET DRIVE_SPEC
  2564.                CALL    WRITE_STRING
  2565.                MOV     SI,VOLUME_NAME[BP]
  2566.                CALL    WRITE_STRING
  2567.  
  2568. ;----------------------------------------------;
  2569.  
  2570. STATS:         MOV     AL,ROWS
  2571.                SUB     AL,5
  2572.                XOR     AH,AH
  2573.                CALL    CALC_COL
  2574.                ADD     DI,34
  2575.                PUSH    DI
  2576.                MOV     AX,DIR_COUNT[BP]
  2577.                CALL    DISP_STATS
  2578.                MOV     SI,OFFSET DIRECTORIES
  2579.                CALL    WRITE_STRING
  2580.                POP     DI
  2581.                ADD     DI,CRT_WIDTH
  2582.  
  2583.                PUSH    DI
  2584.                MOV     AX,TOTAL_CLUSTERS[BP]
  2585.                MUL     BYTES_CLUSTERS[BP]
  2586.                CALL    DISP_STATS
  2587.                MOV     SI,OFFSET BYTES
  2588.                CALL    WRITE_STRING
  2589.                MOV     SI,OFFSET TOTAL
  2590.                CALL    WRITE_STRING
  2591.                POP     DI
  2592.                ADD     DI,CRT_WIDTH
  2593.  
  2594.                PUSH    DI
  2595.                MOV     AX,TOTAL_CLUSTERS[BP]
  2596.                SUB     AX,FREE_CLUSTERS[BP]
  2597.                PUSH    AX
  2598.                MUL     BYTES_CLUSTERS[BP]
  2599.                CALL    DISP_STATS
  2600.                MOV     SI,OFFSET BYTES
  2601.                CALL    WRITE_STRING
  2602.                MOV     SI,OFFSET USED
  2603.                CALL    WRITE_STRING
  2604.                POP     AX
  2605.                CALL    DISP_PERCENT
  2606.                POP     DI
  2607.                ADD     DI,CRT_WIDTH
  2608.  
  2609.                MOV     AX,BYTES_CLUSTERS[BP]
  2610.                MUL     FREE_CLUSTERS[BP]
  2611.                CALL    DISP_STATS
  2612.                MOV     SI,OFFSET BYTES
  2613.                CALL    WRITE_STRING
  2614.                MOV     SI,OFFSET FREE
  2615.                CALL    WRITE_STRING
  2616.                MOV     AX,100
  2617.                MOV     AX,FREE_CLUSTERS[BP]
  2618.                CALL    DISP_PERCENT
  2619.                CALL    DISPLAY_TREE
  2620. DRIVE_END:     RET
  2621.  
  2622. ;----------------------------------------------;
  2623. ; INPUT: AX = CLUSTERS
  2624.  
  2625. DISP_PERCENT:  PUSH    BP
  2626.                MOV     SI,100
  2627.                MUL     SI
  2628.                MOV     BP,TOTAL_CLUSTERS[BP]
  2629.                DIV     BP
  2630.                SHL     DX,1
  2631.                INC     DX
  2632.                SUB     BP,DX
  2633.                ADC     AX,0
  2634.  
  2635.                CMP     AX,100
  2636.                JNZ     DO_PERCENT
  2637.                MOV     SI,OFFSET PERCENT_100
  2638.                CALL    WRITE_STRING
  2639.                JMP     SHORT PERCENT_END
  2640.  
  2641. DO_PERCENT:    PUSH    AX
  2642.                MOV     AL,SPACE
  2643.                CALL    WRITE_SCREEN
  2644.                POP     AX
  2645.                CALL    DECIMAL_ASCII
  2646. DO_PERCENT2:   MOV     AL,"%"
  2647.                CALL    WRITE_SCREEN
  2648. PERCENT_END:   POP     BP
  2649.                RET
  2650.  
  2651. ;----------------------------------------------;
  2652. ; INPUT: DX:AX = number; DI -> Display
  2653.  
  2654. DISP_STATS:    PUSH    BP
  2655.                PUSH    BX
  2656.                MOV     BP,DX
  2657.                MOV     SI,AX
  2658.                XOR     CX,CX
  2659.                MOV     BX,10
  2660.                JMP     SHORT DO_DIV
  2661.  
  2662. NEXT_DIV:      CMP     CH,3
  2663.                JNZ     DO_DIV
  2664.                MOV     AL,","
  2665.                PUSH    AX
  2666.                XOR     CH,CH
  2667.                INC     CL
  2668.  
  2669. DO_DIV:        MOV     AX,BP
  2670.                XOR     DX,DX
  2671.                DIV     BX
  2672.                MOV     BP,AX
  2673.                MOV     AX,SI
  2674.                DIV     BX
  2675.                MOV     SI,AX
  2676.                MOV     AX,DX
  2677.                ADD     AL,"0"
  2678.                PUSH    AX
  2679.                ADD     CX,0101H
  2680.                OR      BP,BP
  2681.                JNZ     NEXT_DIV
  2682.                OR      SI,SI
  2683.                JNZ     NEXT_DIV
  2684.  
  2685.                XOR     CH,CH
  2686.                SUB     DI,CX
  2687.                SUB     DI,CX
  2688.                MOV     BH,TREE_COLOR
  2689. NEXT_WRITE:    POP     AX
  2690.                CALL    WRITE_SCREEN
  2691.                LOOP    NEXT_WRITE
  2692.                POP     BX
  2693.                POP     BP
  2694.                RET
  2695.  
  2696. ;----------------------------------------------;
  2697. ; INPUT: AX = Number.
  2698.  
  2699. DECIMAL_ASCII: MOV     DL,10
  2700.                DIV     DL
  2701.                ADD     AX,"0" SHL 8 + "0"
  2702.                PUSH    AX
  2703.                CMP     AL,"0"
  2704.                JNZ     DO_DECIMAL
  2705.                MOV     AL,SPACE
  2706. DO_DECIMAL:    CALL    WRITE_SCREEN
  2707.                POP     AX
  2708.                MOV     AL,AH
  2709.                CALL    WRITE_SCREEN
  2710.                RET
  2711.  
  2712. ;----------------------------------------------;
  2713.  
  2714. SETUP_COLOR:   MOV     AL,COLOR.I
  2715.                CMP     BP,ACTIVE_TREE
  2716.                JZ      STORE_COLOR
  2717.                MOV     AL,COLOR.W
  2718. STORE_COLOR:   MOV     TREE_COLOR,AL
  2719.                RET
  2720.  
  2721. ;----------------------------------------------;
  2722. ; INPUT: BP = Tree Index; CH = Starting row; AL = Size.
  2723.  
  2724. CLEAR_WINDOW:  MOV     DH,CH
  2725.                ADD     DH,AL
  2726.                XOR     CL,CL
  2727.                OR      BP,BP
  2728.                JZ      CLEAR
  2729.                MOV     CL,41
  2730. CLEAR:         MOV     DL,CL
  2731.                ADD     DL,38
  2732.                MOV     BH,TREE_COLOR
  2733. DO_CLEAR:      MOV     AX,600H
  2734.                push    bp
  2735.                INT     10H
  2736.                pop     bp
  2737.                RET
  2738.  
  2739. ;----------------------------------------------;
  2740. SETUP:         MOV     DX,OFFSET READING
  2741.                CALL    PRINT_STRING
  2742.                XOR     BP,BP
  2743.                CALL    READ_DRIVE
  2744.                JC      INVALID
  2745.                MOV     AL,TREE_DRIVE[BP]
  2746.                INC     BP
  2747.                INC     BP
  2748.                CMP     AL,TREE_DRIVE[BP]
  2749.                JNZ     READ_SECOND
  2750.  
  2751.                CALL    DUP_TREE
  2752.                JMP     SHORT DO_VIDEO
  2753.  
  2754. READ_SECOND:   CALL    READ_DRIVE
  2755.                JNC     DO_VIDEO
  2756. INVALID:       JMP     PARSE_ERROR
  2757.  
  2758. DO_VIDEO:      CALL    VIDEO_SETUP
  2759.  
  2760. ;----------------------------------------------;
  2761.  
  2762. UPDATE_TREE:   XOR     BP,BP
  2763. NEXT_TREE:     CALL    CLEAR_DRIVE
  2764.                CALL    DISPLAY_DRIVE
  2765.                INC     BP
  2766.                INC     BP
  2767.                CMP     BP,2
  2768.                JNA     NEXT_TREE
  2769.                MOV     BP,ACTIVE_TREE
  2770.                RET
  2771.  
  2772. ;----------------------------------------------;
  2773.  
  2774. DUP_TREE:      PUSH    DS
  2775.                PUSH    ES
  2776.  
  2777.                MOV     SI,OFFSET VOLUME1
  2778.                MOV     DI,OFFSET VOLUME2
  2779.                MOV     CX,VOLUME_LEN
  2780.                REP     MOVSB
  2781.  
  2782.                MOV     AX,DIR_COUNT[0]
  2783.                MOV     DIR_COUNT[2],AX
  2784.                MOV     AX,FREE_CLUSTERS[0]
  2785.                MOV     FREE_CLUSTERS[2],AX
  2786.                MOV     AX,TOTAL_CLUSTERS[0]
  2787.                MOV     TOTAL_CLUSTERS[2],AX
  2788.                MOV     AX,BYTES_CLUSTERS[0]
  2789.                MOV     BYTES_CLUSTERS[2],AX
  2790.  
  2791.                MOV     ES,TREE_SEG[2]
  2792.                MOV     DS,TREE_SEG[0]
  2793.                XOR     SI,SI
  2794.                XOR     DI,DI
  2795.                MOV     CX,MAX_ENTRIES * SIZE TREE
  2796.                SHR     CX,1
  2797.                REP     MOVSW
  2798.                ADC     CX,CX
  2799.                REP     MOVSB
  2800.                POP     ES
  2801.                POP     DS
  2802.                CALL    CK_VARS
  2803.                RET
  2804.  
  2805. ;----------------------------------------------;
  2806.  
  2807. CK_VARS:       PUSH    ES
  2808.                MOV     ES,TREE_SEG[BP]
  2809. NEXT_VARS:     MOV     AX,SIZE TREE
  2810.                MUL     BAR_LINE[BP]
  2811.                MOV     DI,AX
  2812.                INC     DI
  2813.                XOR     AL,AL
  2814.                MOV     CX,SIZE TREE - 1
  2815.                REP     SCASB
  2816.                JNZ     VARS_END
  2817.                DEC     BAR_LINE[BP]
  2818.                MOV     AX,BAR_LINE[BP]
  2819.                CMP     AX,LISTING_TOP[BP]
  2820.                JAE     NEXT_VARS
  2821.                DEC     LISTING_TOP[BP]
  2822.                JMP     NEXT_VARS
  2823. VARS_END:      POP     ES
  2824.                RET
  2825.  
  2826. ;----------------------------------------------;
  2827.  
  2828. CLEAR_DRIVE:   CALL    SETUP_COLOR
  2829.                MOV     CH,1                    ;Starting row 1
  2830.                XOR     AL,AL                   ;Window size.
  2831.                CALL    CLEAR_WINDOW
  2832.                MOV     CH,ROWS
  2833.                SUB     CH,5
  2834.                MOV     AL,3
  2835.                CALL    CLEAR_WINDOW
  2836.                RET
  2837.  
  2838. ;----------------------------------------------;
  2839. ; INPUT: DS:SI -> Directory record.  OUTPUT: CF=1 if failed.
  2840.  
  2841. SELECT_DIR:    PUSH    SI
  2842.                PUSH    DS
  2843.                MOV     AX,CS
  2844.                MOV     DS,AX
  2845.                MOV     DX,OFFSET ROOT_DIR
  2846.                CALL    CHANGE_DIR
  2847.                POP     DS
  2848.  
  2849.                OR      SI,SI
  2850.                JZ      SELECT_END
  2851.                CALL    GET_NAME
  2852.                XOR     CX,CX                   ;Zero in level counter.
  2853.  
  2854. NEXT_SUBDIR:   PUSH    SI
  2855.                INC     CX
  2856.                CALL    FIND_PARENT
  2857.                CMP     SI,1
  2858.                JA      NEXT_SUBDIR
  2859.  
  2860. CHANGE_THEM:   POP     DX                      ;Retrieve directory name pointer.
  2861.                CALL    CHANGE_DIR              ;Change directories.
  2862.                JC      RESTORE_STACK           ;If nonexistant, restore stack
  2863.                LOOP    CHANGE_THEM             ;Else, continue up the tree.
  2864. SELECT_END:    CLC
  2865.                POP     SI
  2866.                RET
  2867.  
  2868. NEXT_STACK:    POP     DX                      ;If error, restore stack
  2869. RESTORE_STACK: LOOP    NEXT_STACK              ; before returning.
  2870.                STC
  2871.                POP     SI
  2872.                RET
  2873.  
  2874. ;----------------------------------------------;
  2875. ; INPUT:  AL=Drive Letter; BP = Tree Index; SI -> ":"
  2876. ; OUTPUT: DL=Drive Number; ZF=0 if exists
  2877.  
  2878. DRIVEEXIST:    MOV     DL,AL
  2879.                AND     DL,5FH
  2880.                SUB     DL,"A"
  2881.                CMP     BYTE PTR [SI],":"
  2882.                JNZ     DRIVEEXIST_END
  2883.                CMP     BYTE PTR [SI+1],SPACE
  2884.                JA      DRIVEEXIST_END
  2885.                DEC     SI
  2886.                MOV     DI,DEFAULT_PATH[BP]
  2887.                MOV     AX,2900H                ;Parse filename.
  2888.                INT     21H
  2889. DRIVEEXIST_END:OR      AL,AL
  2890.                RET
  2891.  
  2892. ;-------------------------------------------------;
  2893. ; INPUT: BP = Tree Index.
  2894.  
  2895. RESTORE_DIR:   MOV     DL,TREE_DRIVE[BP]
  2896.                MOV     AH,0EH
  2897.                INT     21H
  2898.                MOV     DX,DEFAULT_PATH[BP]
  2899.                CALL    CHANGE_DIR
  2900.                RET
  2901.  
  2902. ;----------------------------------------------;
  2903.  
  2904. VIDEO_SETUP:   PUSH    ES
  2905.                MOV     AX,500H                 ;Make sure active page is zero.
  2906.                INT     10H
  2907.                MOV     AX,40H                  ;Point to the ROM BIOS data area
  2908.                MOV     ES,AX
  2909.                MOV     AX,ES:CRT_COLS
  2910.                MOV     COLUMNS,AX
  2911.                SHL     AX,1
  2912.                MOV     CRT_WIDTH,AX
  2913.                MOV     AX,ES:[4EH]
  2914.                MOV     CRT_START,AX
  2915.  
  2916.                MOV     AX,ES:[63H]
  2917.                ADD     AX,6
  2918.                MOV     CX,0B000H
  2919.                CMP     AX,3BAH
  2920.                JZ      STORE_SEG
  2921.                ADD     CX,800H
  2922. STORE_SEG:     MOV     STATUS_REG,AX
  2923.                MOV     VIDEO_SEG,CX
  2924.  
  2925.                MOV     SI,OFFSET MONO_ATTR
  2926.                MOV     AL,ES:CRT_MODE          ;Retrieve current video mode.
  2927.                CMP     AL,7                    ;Is it mono mode?
  2928.                JZ      GET_ROWS                ;If yes, continue.
  2929.                CMP     AL,2                    ;Is it BW80?
  2930.                JZ      GET_ROWS                ;If yes, continue.
  2931.                MOV     SI,OFFSET COLOR_ATTR
  2932.                CMP     AL,3                    ;Is it mode CO80?
  2933.                JZ      GET_ROWS                ;If yes, continue.
  2934.                MOV     AX,3                    ;Else, change video mode to CO80.
  2935.                INT     10H
  2936.  
  2937. GET_ROWS:      XOR     BH,BH
  2938.                MOV     DL,24
  2939.                MOV     AX,1130H
  2940.                INT     10H
  2941.                MOV     ROWS,DL                 ;Store rows.
  2942.                SUB     DL,7
  2943.                XOR     DH,DH
  2944.                MOV     LISTING_LEN,DX
  2945.  
  2946.                POP     ES
  2947.                MOV     DI,OFFSET COLOR
  2948.                MOV     CX,SIZE COLOR_ATTRIBS
  2949.                REP     MOVSB
  2950.  
  2951. ;----------------------------------------------;
  2952.  
  2953. DISPLAY_SETUP: CALL    CLS                     ;Clear screen.
  2954.  
  2955.                CMP     BORDER_FLAG,1
  2956.                JZ      DO_COPYRIGHT
  2957.                MOV     BL,COLOR.W              ;Turn on border.
  2958.                AND     BL,7
  2959.                XOR     BH,BH
  2960.                MOV     AH,0BH
  2961.                INT     10H
  2962.  
  2963. DO_COPYRIGHT:  XOR     AX,AX
  2964.                CALL    CALC_ADDR
  2965.                INC     DI
  2966.                INC     DI
  2967.                MOV     SI,OFFSET COPYRIGHT     ;Point to copyright message.
  2968.                MOV     BH,COLOR.B              ;Use header attribute.
  2969.                CALL    WRITE_STRING            ;And display it.
  2970.                MOV     AL,BOX
  2971.                CALL    WRITE_SCREEN
  2972.                MOV     AL,SPACE
  2973.                CALL    WRITE_SCREEN
  2974.                INC     SI                      ;Bump pointer past LF
  2975.                CALL    WRITE_STRING            ; and display rest of header.
  2976.  
  2977. ;----------------------------------------------;
  2978.  
  2979. DISPLAY_MENU:  MOV     AL,ROWS
  2980.                DEC     AL
  2981.                XOR     AH,AH
  2982.                CALL    CALC_ADDR
  2983.                MOV     SI,OFFSET MENU
  2984.                PUSH    DI
  2985.                MOV     BH,COLOR.B
  2986.                CALL    WRITE_STRING
  2987.                POP     DI
  2988.                ADD     DI,CRT_WIDTH
  2989.                CALL    WRITE_STRING
  2990.                RET
  2991.  
  2992. ;----------------------------------------------;
  2993. ; INPUT: AX = Starting line; BP = Tree Index; OUTPUT: DI = Video address.
  2994.  
  2995. CALC_COL:      CALL    CALC_ADDR
  2996.                OR      BP,BP
  2997.                JZ      COL_END
  2998.                ADD     DI,COLUMNS
  2999.                INC     DI
  3000.                INC     DI
  3001. COL_END:       RET
  3002.  
  3003. ;----------------------------------------------;
  3004. ; INPUT: AX = Starting line; OUTPUT: DI = Video address.
  3005.  
  3006. CALC_ADDR:     MUL     CRT_WIDTH
  3007.                ADD     AX,CRT_START
  3008.                MOV     DI,AX
  3009.                RET
  3010.  
  3011. ;----------------------------------------------;
  3012. ; INPUT:  AL = character to write;  BH = attribute.
  3013.  
  3014. WRITE_SCREEN:  PUSH    ES
  3015.                MOV     ES,CS:VIDEO_SEG         ;Point to screen segment.
  3016.                MOV     DX,CS:STATUS_REG        ;Retrieve status register.
  3017.                MOV     BL,AL                   ;Store character in BL.
  3018.  
  3019. HORZ_RET:      IN      AL,DX                   ;Get status.
  3020.                RCR     AL,1                    ;Is it low?
  3021.                JC      HORZ_RET                ;If not, wait until it is.
  3022.                CLI                             ;No more interrupts.
  3023.  
  3024. HWAIT:         IN      AL,DX                   ;Get status.
  3025.                RCR     AL,1                    ;Is it high?
  3026.                JNC     HWAIT                   ;If no, wait until it is.
  3027.  
  3028.                MOV     AX,BX                   ;Retrieve character; now it's OK
  3029.                STOSW                           ; to write to screen buffer.
  3030.                STI                             ;Interrupts back on.
  3031.                POP     ES
  3032.                RET                             ;Return
  3033.  
  3034. ;----------------------------------------------;
  3035. ; INPUT:  SI -> to string to display;  DI -> where to display it.
  3036. ;   Entry point is WRITE_STRING.
  3037.  
  3038. WRITE_IT:      CALL    WRITE_SCREEN            ;Write a character.
  3039. WRITE_STRING:  LODSB                           ;Retrieve a character.
  3040.                CMP     AL,CR                   ;Keep writing until a carriage
  3041.                JA      WRITE_IT                ; return or zero encountered.
  3042.                RET
  3043.  
  3044. ;----------------------------------------------;
  3045. ; INPUT: DL = Drive Number.
  3046.  
  3047. SELECT_DISK:   MOV     AH,0EH
  3048.                INT     21H
  3049.                RET
  3050.  
  3051. ;----------------------------------------------;
  3052. ; INPUT: SI -> Path Storage; DL=Drive Number
  3053.  
  3054. GET_DIR:       MOV     BYTE PTR [SI],"\"       ;DOS doesn't preface directory
  3055.                INC     SI                      ; with slash so we must.
  3056. CHDIR:         PUSH    DX
  3057.                INC     DL
  3058.                MOV     AH,47H                  ;Get current directory.
  3059.                INT     21H
  3060.                POP     DX
  3061.                RET
  3062.  
  3063. CHANGE_DIR:    MOV     AH,3BH                  ;Change current directory.
  3064.                INT     21H
  3065.                RET
  3066.  
  3067. ;----------------------------------------------;
  3068.  
  3069. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  3070.                INT     21H
  3071.                RET
  3072.  
  3073. ;----------------------------------------------;
  3074. ; OUTPUT: CF=1 if failed.
  3075.  
  3076. DISK_FREE:     PUSH    DS
  3077.                PUSH    CS
  3078.                POP     DS
  3079.                PUSH    BX
  3080.                CALL    DOS_CURSOR
  3081.                MOV     DL,TREE_DRIVE[BP]
  3082.                INC     DL
  3083.                MOV     AH,36H                  ;Disk free space.
  3084.                INT     21H
  3085.                CMP     AX,-1
  3086.                STC
  3087.                JZ      FREE_END
  3088.                MOV     FREE_CLUSTERS[BP],BX
  3089.                MOV     TOTAL_CLUSTERS[BP],DX
  3090.                MUL     CX
  3091.                MOV     BYTES_CLUSTERS[BP],AX
  3092.  
  3093.                CLC
  3094. FREE_END:      POP     BX
  3095.                POP     DS
  3096.                RET
  3097.  
  3098. ;----------------------------------------------;
  3099.  
  3100. BEEP:          MOV     BX,NOTE                 ;Tone frequency divisor.
  3101.                MOV     DX,12H
  3102.                XOR     AX,AX
  3103.                DIV     BX
  3104.                MOV     BX,AX                   ;8253 countdown.
  3105.  
  3106.                CALL    DELAY                   ;Wait till clock rolls over.
  3107.  
  3108.                MOV     AL,0B6H                 ;Channel 2 speaker functions.
  3109.                OUT     43H,AL                  ;8253 Mode Control.
  3110.                JMP     $+2                     ;IO delay.
  3111.                MOV     AX,BX                   ;Retrieve countdown.
  3112.                OUT     42H,AL                  ;Channel 2 LSB.
  3113.                JMP     $+2
  3114.                MOV     AL,AH                   ;Channel 2 MSB.
  3115.                OUT     42H,AL
  3116.                IN      AL,61H                  ;Port B.
  3117.                OR      AL,3                    ;Turn on speaker.
  3118.                JMP     $+2
  3119.                OUT     61H,AL
  3120.  
  3121.                CALL    DELAY                   ;Delay one second.
  3122.                IN      AL,61H                  ;Get Port B again.
  3123.                AND     AL,NOT 3                ;Turn speaker off.
  3124.                JMP     $+2
  3125.                OUT     61H,AL
  3126.                RET                             ;Done.
  3127.  
  3128. ;----------------------------------------------;
  3129.  
  3130. DELAY:         PUSH    DS                      ;Preserve data segment.
  3131.                MOV     AX,40H                  ;Point to BIOS data segment.
  3132.                MOV     DS,AX
  3133.                MOV     AX,DS:[6CH]             ;Retrieve timer low.
  3134. NEXT_BEEP:     MOV     DX,DS:[6CH]             ;Retrieve timer low.
  3135.                CMP     DX,AX                   ;Have we timed out?
  3136.                JZ      NEXT_BEEP               ;If not, wait until second up.
  3137.                POP     DS                      ;Restore data segment.
  3138.                RET
  3139.  
  3140. ;----------------------------------------------;
  3141.  
  3142. CLS:           MOV     BH,COLOR.B              ;Normal attribute.
  3143. CLS2:          XOR     CX,CX                   ;Top left corner.
  3144.                MOV     DL,BYTE PTR COLUMNS
  3145.                DEC     DL
  3146.                MOV     DH,ROWS
  3147.                MOV     AX,600H                 ;Scroll active page.
  3148.                PUSH    BP
  3149.                INT     10H
  3150.                POP     BP
  3151.                RET
  3152.  
  3153. ;----------------------------------------------;
  3154.  
  3155. DOS_CURSOR:    MOV     DX,200H                 ;Put cursor on screen in case
  3156.                JMP     SHORT SET_CURSOR        ; of critical error like drive
  3157.                                                ; drive door open.
  3158.  
  3159. HIDE_CURSOR:   MOV     DH,ROWS                 ;Retrieve CRT rows.
  3160.                INC     DH                      ;Move one line below off screen.
  3161.                XOR     DL,DL                   ;Column zero.
  3162.  
  3163. SET_CURSOR:    PUSH    BX
  3164.                XOR     BH,BH                   ;Page zero.
  3165.                MOV     AH,2                    ;Set cursor position.
  3166.                INT     10H
  3167.                POP     BX
  3168.                RET
  3169.  
  3170. ;----------------------------------------------;
  3171. ; INPUT:  DI -> Valid scan codes table; CX = Length of table
  3172. ; OUTPUT: AL=Scan code; AH=Char; CF=1 if Esc pressed.
  3173.  
  3174. DISPATCH:      CALL    GET_KEY
  3175.                PUSH    AX
  3176.                CMP     AL,ESC_SCAN
  3177.                STC
  3178.                JZ      DISPATCH_END
  3179.                CMP     AH,CR
  3180.                JZ      DISPATCH_END
  3181.                MOV     BX,CX
  3182.                MOV     DX,DI
  3183.                ADD     DX,CX
  3184.                REPNZ   SCASB
  3185.                JZ      GOT_DISPATCH
  3186.                CALL    SEARCH
  3187.                JMP     SHORT NO_DISPATCH
  3188.  
  3189. GOT_DISPATCH:  SUB     BX,CX
  3190.                DEC     BX
  3191.                SHL     BX,1
  3192.                ADD     BX,DX
  3193.                MOV     AX,DIR_COUNT[BP]
  3194.                DEC     AX
  3195.                MOV     CX,BAR_LINE[BP]
  3196.                MOV     DX,LISTING_TOP[BP]
  3197.                MOV     DI,DX
  3198.                MOV     SI,LISTING_LEN
  3199.                ADD     DI,SI
  3200.                DEC     DI
  3201.                CMP     DI,AX
  3202.                JBE     DO_DISPATCH
  3203.                MOV     DI,AX
  3204. DO_DISPATCH:   CALL    [BX]                    ;Process the command.
  3205. NO_DISPATCH:   CLC
  3206. DISPATCH_END:  POP     AX
  3207.                RET
  3208.  
  3209. ;----------------------------------------------;
  3210.  
  3211. SEARCH:        PUSH    DS
  3212.                OR      AL,AL
  3213.                JZ      NO_MATCH
  3214.                CMP     AH,"a"
  3215.                JB      DO_SEARCH
  3216.                CMP     AH,"z"
  3217.                JA      DO_SEARCH
  3218.                AND     AH,5FH
  3219.  
  3220. DO_SEARCH:     MOV     BL,AH
  3221.                MOV     AX,SIZE TREE
  3222.                MOV     CX,BAR_LINE[BP]
  3223.                MUL     CX
  3224.                MOV     SI,AX
  3225.                MOV     DS,TREE_SEG[BP]
  3226.                PUSH    SI
  3227.                CALL    GET_NAME
  3228.                CMP     BL,BYTE PTR [SI]
  3229.                POP     SI
  3230.                JZ      NEXT_SEARCH
  3231.                XOR     SI,SI
  3232.                XOR     CX,CX
  3233.  
  3234. NEXT_SEARCH:   INC     CX
  3235.                CMP     CX,CS:DIR_COUNT[BP]
  3236.                JAE     NO_MATCH
  3237.                ADD     SI,SIZE TREE
  3238.                PUSH    SI
  3239.                CALL    GET_NAME
  3240.                CMP     BL,BYTE PTR [SI]
  3241.                POP     SI
  3242.                JNZ     NEXT_SEARCH
  3243.  
  3244.                POP     DS
  3245.                MOV     BAR_LINE[BP],CX
  3246.                MOV     AX,LISTING_TOP[BP]
  3247.                MOV     BX,LISTING_LEN
  3248.                CMP     CX,AX
  3249.                JB      CENTER_BAR
  3250.                ADD     AX,BX
  3251.                DEC     AX
  3252.                CMP     CX,AX
  3253.                JBE     SEARCH_END
  3254.  
  3255. CENTER_BAR:    SHR     BX,1
  3256.                SUB     CX,BX
  3257.                JNC     NEW_TOP
  3258.                XOR     CX,CX
  3259. NEW_TOP:       MOV     LISTING_TOP[BP],CX
  3260. SEARCH_END:    CALL    DISPLAY_TREE
  3261.                RET
  3262.  
  3263. NO_MATCH:      POP     DS
  3264.                CALL    BEEP
  3265.                RET
  3266.  
  3267. ;----------------------------------------------;
  3268.  
  3269. GET_KEY:       MOV     AH,0                    ;Wait for next keyboard input.
  3270.                INT     16H
  3271.                XCHG    AH,AL
  3272.                RET
  3273.  
  3274. CK_KEY:        MOV     AH,1                    ;Is there a keystroke available.
  3275.                INT     16H
  3276.                RET
  3277.  
  3278. CLEAR_IT:      CALL    GET_KEY                 ;Read keystrokes until buffer
  3279. CLEAR_KEY:     CALL    CK_KEY                  ; empty.
  3280.                JNZ     CLEAR_IT
  3281.                RET
  3282.  
  3283. ;----------------------------------------------;
  3284.  
  3285. WRITE_TTY:     MOV     AH,0EH
  3286.                INT     10H
  3287.                RET
  3288.  
  3289. ;----------------------------------------------;
  3290.  
  3291. DEFAULT_DIR1   =  $
  3292. DEFAULT_DIR2   =  DEFAULT_DIR1 + 65
  3293. DEST_SPEC      =  DEFAULT_DIR2 + 65
  3294. LEVEL_ADDRESS  =  DEST_SPEC + 65 + 13
  3295. EVEN
  3296. STACK_POINTER  =  $ + 100 + 500
  3297.  
  3298. _TEXT          ENDS
  3299.                END     START
  3300.